mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-29 02:52:13 +00:00
Merge pull request #58334 from Algunenano/minmax_non_numeric
Speedup MIN/MAX for non numeric types
This commit is contained in:
commit
0522d859c2
@ -1,7 +1,8 @@
|
|||||||
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
||||||
#include <AggregateFunctions/FactoryHelpers.h>
|
#include <AggregateFunctions/FactoryHelpers.h>
|
||||||
#include <AggregateFunctions/HelpersMinMaxAny.h>
|
#include <AggregateFunctions/HelpersMinMaxAny.h>
|
||||||
#include <AggregateFunctions/findNumeric.h>
|
#include <Common/Concepts.h>
|
||||||
|
#include <Common/findExtreme.h>
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -19,7 +20,7 @@ public:
|
|||||||
explicit AggregateFunctionsSingleValueMax(const DataTypePtr & type) : Parent(type) { }
|
explicit AggregateFunctionsSingleValueMax(const DataTypePtr & type) : Parent(type) { }
|
||||||
|
|
||||||
/// Specializations for native numeric types
|
/// Specializations for native numeric types
|
||||||
ALWAYS_INLINE inline void addBatchSinglePlace(
|
void addBatchSinglePlace(
|
||||||
size_t row_begin,
|
size_t row_begin,
|
||||||
size_t row_end,
|
size_t row_end,
|
||||||
AggregateDataPtr __restrict place,
|
AggregateDataPtr __restrict place,
|
||||||
@ -27,7 +28,7 @@ public:
|
|||||||
Arena * arena,
|
Arena * arena,
|
||||||
ssize_t if_argument_pos) const override;
|
ssize_t if_argument_pos) const override;
|
||||||
|
|
||||||
ALWAYS_INLINE inline void addBatchSinglePlaceNotNull(
|
void addBatchSinglePlaceNotNull(
|
||||||
size_t row_begin,
|
size_t row_begin,
|
||||||
size_t row_end,
|
size_t row_end,
|
||||||
AggregateDataPtr __restrict place,
|
AggregateDataPtr __restrict place,
|
||||||
@ -53,10 +54,10 @@ void AggregateFunctionsSingleValueMax<typename DB::AggregateFunctionMaxData<Sing
|
|||||||
if (if_argument_pos >= 0) \
|
if (if_argument_pos >= 0) \
|
||||||
{ \
|
{ \
|
||||||
const auto & flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData(); \
|
const auto & flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData(); \
|
||||||
opt = findNumericMaxIf(column.getData().data(), flags.data(), row_begin, row_end); \
|
opt = findExtremeMaxIf(column.getData().data(), flags.data(), row_begin, row_end); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
opt = findNumericMax(column.getData().data(), row_begin, row_end); \
|
opt = findExtremeMax(column.getData().data(), row_begin, row_end); \
|
||||||
if (opt.has_value()) \
|
if (opt.has_value()) \
|
||||||
this->data(place).changeIfGreater(opt.value()); \
|
this->data(place).changeIfGreater(opt.value()); \
|
||||||
}
|
}
|
||||||
@ -74,7 +75,57 @@ void AggregateFunctionsSingleValueMax<Data>::addBatchSinglePlace(
|
|||||||
Arena * arena,
|
Arena * arena,
|
||||||
ssize_t if_argument_pos) const
|
ssize_t if_argument_pos) const
|
||||||
{
|
{
|
||||||
return Parent::addBatchSinglePlace(row_begin, row_end, place, columns, arena, if_argument_pos);
|
if constexpr (!is_any_of<typename Data::Impl, SingleValueDataString, SingleValueDataGeneric>)
|
||||||
|
{
|
||||||
|
/// Leave other numeric types (large integers, decimals, etc) to keep doing the comparison as it's
|
||||||
|
/// faster than doing a permutation
|
||||||
|
return Parent::addBatchSinglePlace(row_begin, row_end, place, columns, arena, if_argument_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int nan_direction_hint = 1;
|
||||||
|
auto const & column = *columns[0];
|
||||||
|
if (if_argument_pos >= 0)
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
const auto & if_flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData();
|
||||||
|
while (if_flags[index] == 0 && index < row_end)
|
||||||
|
index++;
|
||||||
|
if (index >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if ((if_flags[i] != 0) && (column.compareAt(i, index, column, nan_direction_hint) > 0))
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfGreater(column, index, arena);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (row_begin >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/// TODO: Introduce row_begin and row_end to getPermutation
|
||||||
|
if (row_begin != 0 || row_end != column.size())
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if (column.compareAt(i, index, column, nan_direction_hint) > 0)
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfGreater(column, index, arena);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constexpr IColumn::PermutationSortDirection direction = IColumn::PermutationSortDirection::Descending;
|
||||||
|
constexpr IColumn::PermutationSortStability stability = IColumn::PermutationSortStability::Unstable;
|
||||||
|
IColumn::Permutation permutation;
|
||||||
|
constexpr UInt64 limit = 1;
|
||||||
|
column.getPermutation(direction, stability, limit, nan_direction_hint, permutation);
|
||||||
|
this->data(place).changeIfGreater(column, permutation[0], arena);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTBEGIN(bugprone-macro-parentheses)
|
// NOLINTBEGIN(bugprone-macro-parentheses)
|
||||||
@ -97,10 +148,10 @@ void AggregateFunctionsSingleValueMax<typename DB::AggregateFunctionMaxData<Sing
|
|||||||
auto final_flags = std::make_unique<UInt8[]>(row_end); \
|
auto final_flags = std::make_unique<UInt8[]>(row_end); \
|
||||||
for (size_t i = row_begin; i < row_end; ++i) \
|
for (size_t i = row_begin; i < row_end; ++i) \
|
||||||
final_flags[i] = (!null_map[i]) & !!if_flags[i]; \
|
final_flags[i] = (!null_map[i]) & !!if_flags[i]; \
|
||||||
opt = findNumericMaxIf(column.getData().data(), final_flags.get(), row_begin, row_end); \
|
opt = findExtremeMaxIf(column.getData().data(), final_flags.get(), row_begin, row_end); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
opt = findNumericMaxNotNull(column.getData().data(), null_map, row_begin, row_end); \
|
opt = findExtremeMaxNotNull(column.getData().data(), null_map, row_begin, row_end); \
|
||||||
if (opt.has_value()) \
|
if (opt.has_value()) \
|
||||||
this->data(place).changeIfGreater(opt.value()); \
|
this->data(place).changeIfGreater(opt.value()); \
|
||||||
}
|
}
|
||||||
@ -119,7 +170,46 @@ void AggregateFunctionsSingleValueMax<Data>::addBatchSinglePlaceNotNull(
|
|||||||
Arena * arena,
|
Arena * arena,
|
||||||
ssize_t if_argument_pos) const
|
ssize_t if_argument_pos) const
|
||||||
{
|
{
|
||||||
return Parent::addBatchSinglePlaceNotNull(row_begin, row_end, place, columns, null_map, arena, if_argument_pos);
|
if constexpr (!is_any_of<typename Data::Impl, SingleValueDataString, SingleValueDataGeneric>)
|
||||||
|
{
|
||||||
|
/// Leave other numeric types (large integers, decimals, etc) to keep doing the comparison as it's
|
||||||
|
/// faster than doing a permutation
|
||||||
|
return Parent::addBatchSinglePlaceNotNull(row_begin, row_end, place, columns, null_map, arena, if_argument_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int nan_direction_hint = 1;
|
||||||
|
auto const & column = *columns[0];
|
||||||
|
if (if_argument_pos >= 0)
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
const auto & if_flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData();
|
||||||
|
while ((if_flags[index] == 0 || null_map[index] != 0) && (index < row_end))
|
||||||
|
index++;
|
||||||
|
if (index >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if ((if_flags[i] != 0) && (null_map[i] == 0) && (column.compareAt(i, index, column, nan_direction_hint) > 0))
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfGreater(column, index, arena);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
while ((null_map[index] != 0) && (index < row_end))
|
||||||
|
index++;
|
||||||
|
if (index >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if ((null_map[i] == 0) && (column.compareAt(i, index, column, nan_direction_hint) > 0))
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfGreater(column, index, arena);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AggregateFunctionPtr createAggregateFunctionMax(
|
AggregateFunctionPtr createAggregateFunctionMax(
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
||||||
#include <AggregateFunctions/FactoryHelpers.h>
|
#include <AggregateFunctions/FactoryHelpers.h>
|
||||||
#include <AggregateFunctions/HelpersMinMaxAny.h>
|
#include <AggregateFunctions/HelpersMinMaxAny.h>
|
||||||
#include <AggregateFunctions/findNumeric.h>
|
#include <Common/Concepts.h>
|
||||||
|
#include <Common/findExtreme.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -20,7 +21,7 @@ public:
|
|||||||
explicit AggregateFunctionsSingleValueMin(const DataTypePtr & type) : Parent(type) { }
|
explicit AggregateFunctionsSingleValueMin(const DataTypePtr & type) : Parent(type) { }
|
||||||
|
|
||||||
/// Specializations for native numeric types
|
/// Specializations for native numeric types
|
||||||
ALWAYS_INLINE inline void addBatchSinglePlace(
|
void addBatchSinglePlace(
|
||||||
size_t row_begin,
|
size_t row_begin,
|
||||||
size_t row_end,
|
size_t row_end,
|
||||||
AggregateDataPtr __restrict place,
|
AggregateDataPtr __restrict place,
|
||||||
@ -28,7 +29,7 @@ public:
|
|||||||
Arena * arena,
|
Arena * arena,
|
||||||
ssize_t if_argument_pos) const override;
|
ssize_t if_argument_pos) const override;
|
||||||
|
|
||||||
ALWAYS_INLINE inline void addBatchSinglePlaceNotNull(
|
void addBatchSinglePlaceNotNull(
|
||||||
size_t row_begin,
|
size_t row_begin,
|
||||||
size_t row_end,
|
size_t row_end,
|
||||||
AggregateDataPtr __restrict place,
|
AggregateDataPtr __restrict place,
|
||||||
@ -54,10 +55,10 @@ public:
|
|||||||
if (if_argument_pos >= 0) \
|
if (if_argument_pos >= 0) \
|
||||||
{ \
|
{ \
|
||||||
const auto & flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData(); \
|
const auto & flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData(); \
|
||||||
opt = findNumericMinIf(column.getData().data(), flags.data(), row_begin, row_end); \
|
opt = findExtremeMinIf(column.getData().data(), flags.data(), row_begin, row_end); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
opt = findNumericMin(column.getData().data(), row_begin, row_end); \
|
opt = findExtremeMin(column.getData().data(), row_begin, row_end); \
|
||||||
if (opt.has_value()) \
|
if (opt.has_value()) \
|
||||||
this->data(place).changeIfLess(opt.value()); \
|
this->data(place).changeIfLess(opt.value()); \
|
||||||
}
|
}
|
||||||
@ -75,7 +76,57 @@ void AggregateFunctionsSingleValueMin<Data>::addBatchSinglePlace(
|
|||||||
Arena * arena,
|
Arena * arena,
|
||||||
ssize_t if_argument_pos) const
|
ssize_t if_argument_pos) const
|
||||||
{
|
{
|
||||||
return Parent::addBatchSinglePlace(row_begin, row_end, place, columns, arena, if_argument_pos);
|
if constexpr (!is_any_of<typename Data::Impl, SingleValueDataString, SingleValueDataGeneric>)
|
||||||
|
{
|
||||||
|
/// Leave other numeric types (large integers, decimals, etc) to keep doing the comparison as it's
|
||||||
|
/// faster than doing a permutation
|
||||||
|
return Parent::addBatchSinglePlace(row_begin, row_end, place, columns, arena, if_argument_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int nan_direction_hint = 1;
|
||||||
|
auto const & column = *columns[0];
|
||||||
|
if (if_argument_pos >= 0)
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
const auto & if_flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData();
|
||||||
|
while (if_flags[index] == 0 && index < row_end)
|
||||||
|
index++;
|
||||||
|
if (index >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if ((if_flags[i] != 0) && (column.compareAt(i, index, column, nan_direction_hint) < 0))
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfLess(column, index, arena);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (row_begin >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/// TODO: Introduce row_begin and row_end to getPermutation
|
||||||
|
if (row_begin != 0 || row_end != column.size())
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if (column.compareAt(i, index, column, nan_direction_hint) < 0)
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfLess(column, index, arena);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constexpr IColumn::PermutationSortDirection direction = IColumn::PermutationSortDirection::Ascending;
|
||||||
|
constexpr IColumn::PermutationSortStability stability = IColumn::PermutationSortStability::Unstable;
|
||||||
|
IColumn::Permutation permutation;
|
||||||
|
constexpr UInt64 limit = 1;
|
||||||
|
column.getPermutation(direction, stability, limit, nan_direction_hint, permutation);
|
||||||
|
this->data(place).changeIfLess(column, permutation[0], arena);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTBEGIN(bugprone-macro-parentheses)
|
// NOLINTBEGIN(bugprone-macro-parentheses)
|
||||||
@ -98,10 +149,10 @@ void AggregateFunctionsSingleValueMin<Data>::addBatchSinglePlace(
|
|||||||
auto final_flags = std::make_unique<UInt8[]>(row_end); \
|
auto final_flags = std::make_unique<UInt8[]>(row_end); \
|
||||||
for (size_t i = row_begin; i < row_end; ++i) \
|
for (size_t i = row_begin; i < row_end; ++i) \
|
||||||
final_flags[i] = (!null_map[i]) & !!if_flags[i]; \
|
final_flags[i] = (!null_map[i]) & !!if_flags[i]; \
|
||||||
opt = findNumericMinIf(column.getData().data(), final_flags.get(), row_begin, row_end); \
|
opt = findExtremeMinIf(column.getData().data(), final_flags.get(), row_begin, row_end); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
opt = findNumericMinNotNull(column.getData().data(), null_map, row_begin, row_end); \
|
opt = findExtremeMinNotNull(column.getData().data(), null_map, row_begin, row_end); \
|
||||||
if (opt.has_value()) \
|
if (opt.has_value()) \
|
||||||
this->data(place).changeIfLess(opt.value()); \
|
this->data(place).changeIfLess(opt.value()); \
|
||||||
}
|
}
|
||||||
@ -120,7 +171,46 @@ void AggregateFunctionsSingleValueMin<Data>::addBatchSinglePlaceNotNull(
|
|||||||
Arena * arena,
|
Arena * arena,
|
||||||
ssize_t if_argument_pos) const
|
ssize_t if_argument_pos) const
|
||||||
{
|
{
|
||||||
return Parent::addBatchSinglePlaceNotNull(row_begin, row_end, place, columns, null_map, arena, if_argument_pos);
|
if constexpr (!is_any_of<typename Data::Impl, SingleValueDataString, SingleValueDataGeneric>)
|
||||||
|
{
|
||||||
|
/// Leave other numeric types (large integers, decimals, etc) to keep doing the comparison as it's
|
||||||
|
/// faster than doing a permutation
|
||||||
|
return Parent::addBatchSinglePlaceNotNull(row_begin, row_end, place, columns, null_map, arena, if_argument_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int nan_direction_hint = 1;
|
||||||
|
auto const & column = *columns[0];
|
||||||
|
if (if_argument_pos >= 0)
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
const auto & if_flags = assert_cast<const ColumnUInt8 &>(*columns[if_argument_pos]).getData();
|
||||||
|
while ((if_flags[index] == 0 || null_map[index] != 0) && (index < row_end))
|
||||||
|
index++;
|
||||||
|
if (index >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if ((if_flags[i] != 0) && (null_map[index] == 0) && (column.compareAt(i, index, column, nan_direction_hint) < 0))
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfLess(column, index, arena);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t index = row_begin;
|
||||||
|
while ((null_map[index] != 0) && (index < row_end))
|
||||||
|
index++;
|
||||||
|
if (index >= row_end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = index + 1; i < row_end; i++)
|
||||||
|
{
|
||||||
|
if ((null_map[i] == 0) && (column.compareAt(i, index, column, nan_direction_hint) < 0))
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
this->data(place).changeIfLess(column, index, arena);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AggregateFunctionPtr createAggregateFunctionMin(
|
AggregateFunctionPtr createAggregateFunctionMin(
|
||||||
|
@ -965,6 +965,7 @@ template <typename Data>
|
|||||||
struct AggregateFunctionMinData : Data
|
struct AggregateFunctionMinData : Data
|
||||||
{
|
{
|
||||||
using Self = AggregateFunctionMinData;
|
using Self = AggregateFunctionMinData;
|
||||||
|
using Impl = Data;
|
||||||
|
|
||||||
bool changeIfBetter(const IColumn & column, size_t row_num, Arena * arena) { return this->changeIfLess(column, row_num, arena); }
|
bool changeIfBetter(const IColumn & column, size_t row_num, Arena * arena) { return this->changeIfLess(column, row_num, arena); }
|
||||||
bool changeIfBetter(const Self & to, Arena * arena) { return this->changeIfLess(to, arena); }
|
bool changeIfBetter(const Self & to, Arena * arena) { return this->changeIfLess(to, arena); }
|
||||||
@ -993,6 +994,7 @@ template <typename Data>
|
|||||||
struct AggregateFunctionMaxData : Data
|
struct AggregateFunctionMaxData : Data
|
||||||
{
|
{
|
||||||
using Self = AggregateFunctionMaxData;
|
using Self = AggregateFunctionMaxData;
|
||||||
|
using Impl = Data;
|
||||||
|
|
||||||
bool changeIfBetter(const IColumn & column, size_t row_num, Arena * arena) { return this->changeIfGreater(column, row_num, arena); }
|
bool changeIfBetter(const IColumn & column, size_t row_num, Arena * arena) { return this->changeIfGreater(column, row_num, arena); }
|
||||||
bool changeIfBetter(const Self & to, Arena * arena) { return this->changeIfGreater(to, arena); }
|
bool changeIfBetter(const Self & to, Arena * arena) { return this->changeIfGreater(to, arena); }
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#include <AggregateFunctions/findNumeric.h>
|
|
||||||
|
|
||||||
namespace DB
|
|
||||||
{
|
|
||||||
#define INSTANTIATION(T) \
|
|
||||||
template std::optional<T> findNumericMin(const T * __restrict ptr, size_t start, size_t end); \
|
|
||||||
template std::optional<T> findNumericMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
|
||||||
template std::optional<T> findNumericMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
|
||||||
template std::optional<T> findNumericMax(const T * __restrict ptr, size_t start, size_t end); \
|
|
||||||
template std::optional<T> findNumericMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
|
||||||
template std::optional<T> findNumericMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
|
||||||
|
|
||||||
FOR_BASIC_NUMERIC_TYPES(INSTANTIATION)
|
|
||||||
#undef INSTANTIATION
|
|
||||||
}
|
|
@ -1,18 +1,9 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <DataTypes/IDataType.h>
|
#include <DataTypes/IDataType.h>
|
||||||
#include <base/defines.h>
|
|
||||||
#include <base/types.h>
|
|
||||||
#include <Common/Concepts.h>
|
|
||||||
#include <Common/TargetSpecific.h>
|
#include <Common/TargetSpecific.h>
|
||||||
|
#include <Common/findExtreme.h>
|
||||||
#include <algorithm>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
template <typename T>
|
|
||||||
concept is_any_native_number = (is_any_of<T, Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, Float64>);
|
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
struct MinComparator
|
struct MinComparator
|
||||||
@ -28,8 +19,8 @@ struct MaxComparator
|
|||||||
|
|
||||||
MULTITARGET_FUNCTION_AVX2_SSE42(
|
MULTITARGET_FUNCTION_AVX2_SSE42(
|
||||||
MULTITARGET_FUNCTION_HEADER(template <is_any_native_number T, typename ComparatorClass, bool add_all_elements, bool add_if_cond_zero> static std::optional<T> NO_INLINE),
|
MULTITARGET_FUNCTION_HEADER(template <is_any_native_number T, typename ComparatorClass, bool add_all_elements, bool add_if_cond_zero> static std::optional<T> NO_INLINE),
|
||||||
findNumericExtremeImpl,
|
findExtremeImpl,
|
||||||
MULTITARGET_FUNCTION_BODY((const T * __restrict ptr, const UInt8 * __restrict condition_map [[maybe_unused]], size_t row_begin, size_t row_end)
|
MULTITARGET_FUNCTION_BODY((const T * __restrict ptr, const UInt8 * __restrict condition_map [[maybe_unused]], size_t row_begin, size_t row_end) /// NOLINT
|
||||||
{
|
{
|
||||||
size_t count = row_end - row_begin;
|
size_t count = row_end - row_begin;
|
||||||
ptr += row_begin;
|
ptr += row_begin;
|
||||||
@ -86,69 +77,67 @@ MULTITARGET_FUNCTION_AVX2_SSE42(
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
/// Given a vector of T finds the extreme (MIN or MAX) value
|
/// Given a vector of T finds the extreme (MIN or MAX) value
|
||||||
template <is_any_native_number T, class ComparatorClass, bool add_all_elements, bool add_if_cond_zero>
|
template <is_any_native_number T, class ComparatorClass, bool add_all_elements, bool add_if_cond_zero>
|
||||||
static std::optional<T>
|
static std::optional<T>
|
||||||
findNumericExtreme(const T * __restrict ptr, const UInt8 * __restrict condition_map [[maybe_unused]], size_t start, size_t end)
|
findExtreme(const T * __restrict ptr, const UInt8 * __restrict condition_map [[maybe_unused]], size_t start, size_t end)
|
||||||
{
|
{
|
||||||
#if USE_MULTITARGET_CODE
|
#if USE_MULTITARGET_CODE
|
||||||
/// We see no benefit from using AVX512BW or AVX512F (over AVX2), so we only declare SSE and AVX2
|
/// We see no benefit from using AVX512BW or AVX512F (over AVX2), so we only declare SSE and AVX2
|
||||||
if (isArchSupported(TargetArch::AVX2))
|
if (isArchSupported(TargetArch::AVX2))
|
||||||
return findNumericExtremeImplAVX2<T, ComparatorClass, add_all_elements, add_if_cond_zero>(ptr, condition_map, start, end);
|
return findExtremeImplAVX2<T, ComparatorClass, add_all_elements, add_if_cond_zero>(ptr, condition_map, start, end);
|
||||||
|
|
||||||
if (isArchSupported(TargetArch::SSE42))
|
if (isArchSupported(TargetArch::SSE42))
|
||||||
return findNumericExtremeImplSSE42<T, ComparatorClass, add_all_elements, add_if_cond_zero>(ptr, condition_map, start, end);
|
return findExtremeImplSSE42<T, ComparatorClass, add_all_elements, add_if_cond_zero>(ptr, condition_map, start, end);
|
||||||
#endif
|
#endif
|
||||||
return findNumericExtremeImpl<T, ComparatorClass, add_all_elements, add_if_cond_zero>(ptr, condition_map, start, end);
|
return findExtremeImpl<T, ComparatorClass, add_all_elements, add_if_cond_zero>(ptr, condition_map, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
std::optional<T> findNumericMin(const T * __restrict ptr, size_t start, size_t end)
|
std::optional<T> findExtremeMin(const T * __restrict ptr, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return findNumericExtreme<T, MinComparator<T>, true, false>(ptr, nullptr, start, end);
|
return findExtreme<T, MinComparator<T>, true, false>(ptr, nullptr, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
std::optional<T> findNumericMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
std::optional<T> findExtremeMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return findNumericExtreme<T, MinComparator<T>, false, true>(ptr, condition_map, start, end);
|
return findExtreme<T, MinComparator<T>, false, true>(ptr, condition_map, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
std::optional<T> findNumericMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
std::optional<T> findExtremeMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return findNumericExtreme<T, MinComparator<T>, false, false>(ptr, condition_map, start, end);
|
return findExtreme<T, MinComparator<T>, false, false>(ptr, condition_map, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
std::optional<T> findNumericMax(const T * __restrict ptr, size_t start, size_t end)
|
std::optional<T> findExtremeMax(const T * __restrict ptr, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return findNumericExtreme<T, MaxComparator<T>, true, false>(ptr, nullptr, start, end);
|
return findExtreme<T, MaxComparator<T>, true, false>(ptr, nullptr, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
std::optional<T> findNumericMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
std::optional<T> findExtremeMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return findNumericExtreme<T, MaxComparator<T>, false, true>(ptr, condition_map, start, end);
|
return findExtreme<T, MaxComparator<T>, false, true>(ptr, condition_map, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <is_any_native_number T>
|
template <is_any_native_number T>
|
||||||
std::optional<T> findNumericMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
std::optional<T> findExtremeMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end)
|
||||||
{
|
{
|
||||||
return findNumericExtreme<T, MaxComparator<T>, false, false>(ptr, condition_map, start, end);
|
return findExtreme<T, MaxComparator<T>, false, false>(ptr, condition_map, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define EXTERN_INSTANTIATION(T) \
|
#define INSTANTIATION(T) \
|
||||||
extern template std::optional<T> findNumericMin(const T * __restrict ptr, size_t start, size_t end); \
|
template std::optional<T> findExtremeMin(const T * __restrict ptr, size_t start, size_t end); \
|
||||||
extern template std::optional<T> findNumericMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
template std::optional<T> findExtremeMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
||||||
extern template std::optional<T> findNumericMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
template std::optional<T> findExtremeMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
||||||
extern template std::optional<T> findNumericMax(const T * __restrict ptr, size_t start, size_t end); \
|
template std::optional<T> findExtremeMax(const T * __restrict ptr, size_t start, size_t end); \
|
||||||
extern template std::optional<T> findNumericMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
template std::optional<T> findExtremeMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
||||||
extern template std::optional<T> findNumericMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
template std::optional<T> findExtremeMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
||||||
|
|
||||||
FOR_BASIC_NUMERIC_TYPES(EXTERN_INSTANTIATION)
|
|
||||||
#undef EXTERN_INSTANTIATION
|
|
||||||
|
|
||||||
|
FOR_BASIC_NUMERIC_TYPES(INSTANTIATION)
|
||||||
|
#undef INSTANTIATION
|
||||||
}
|
}
|
45
src/Common/findExtreme.h
Normal file
45
src/Common/findExtreme.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <DataTypes/IDataType.h>
|
||||||
|
#include <base/defines.h>
|
||||||
|
#include <base/types.h>
|
||||||
|
#include <Common/Concepts.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
concept is_any_native_number = (is_any_of<T, Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64, Float32, Float64>);
|
||||||
|
|
||||||
|
template <is_any_native_number T>
|
||||||
|
std::optional<T> findExtremeMin(const T * __restrict ptr, size_t start, size_t end);
|
||||||
|
|
||||||
|
template <is_any_native_number T>
|
||||||
|
std::optional<T> findExtremeMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
||||||
|
|
||||||
|
template <is_any_native_number T>
|
||||||
|
std::optional<T> findExtremeMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
||||||
|
|
||||||
|
template <is_any_native_number T>
|
||||||
|
std::optional<T> findExtremeMax(const T * __restrict ptr, size_t start, size_t end);
|
||||||
|
|
||||||
|
template <is_any_native_number T>
|
||||||
|
std::optional<T> findExtremeMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
||||||
|
|
||||||
|
template <is_any_native_number T>
|
||||||
|
std::optional<T> findExtremeMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
||||||
|
|
||||||
|
#define EXTERN_INSTANTIATION(T) \
|
||||||
|
extern template std::optional<T> findExtremeMin(const T * __restrict ptr, size_t start, size_t end); \
|
||||||
|
extern template std::optional<T> findExtremeMinNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
||||||
|
extern template std::optional<T> findExtremeMinIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
||||||
|
extern template std::optional<T> findExtremeMax(const T * __restrict ptr, size_t start, size_t end); \
|
||||||
|
extern template std::optional<T> findExtremeMaxNotNull(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end); \
|
||||||
|
extern template std::optional<T> findExtremeMaxIf(const T * __restrict ptr, const UInt8 * __restrict condition_map, size_t start, size_t end);
|
||||||
|
|
||||||
|
FOR_BASIC_NUMERIC_TYPES(EXTERN_INSTANTIATION)
|
||||||
|
#undef EXTERN_INSTANTIATION
|
||||||
|
|
||||||
|
}
|
@ -87,4 +87,9 @@
|
|||||||
<query>select any(FromTag) from hits_100m_single where FromTag != '' group by intHash32(UserID) % {group_scale} FORMAT Null</query>
|
<query>select any(FromTag) from hits_100m_single where FromTag != '' group by intHash32(UserID) % {group_scale} FORMAT Null</query>
|
||||||
<query>select anyHeavy(FromTag) from hits_100m_single where FromTag != '' group by intHash32(UserID) % {group_scale} FORMAT Null</query>
|
<query>select anyHeavy(FromTag) from hits_100m_single where FromTag != '' group by intHash32(UserID) % {group_scale} FORMAT Null</query>
|
||||||
|
|
||||||
|
<!-- Test with tuples (useful when you want to keep 2 columns of the same row) -->
|
||||||
|
<query>select min((WatchID, CounterID)) from hits_100m_single FORMAT Null</query>
|
||||||
|
<query>select max((WatchID, CounterID)) from hits_100m_single FORMAT Null</query>
|
||||||
|
<query>select any((WatchID, CounterID)) from hits_100m_single FORMAT Null</query>
|
||||||
|
<query>select anyHeavy((WatchID, CounterID)) from hits_100m_single FORMAT Null</query>
|
||||||
</test>
|
</test>
|
||||||
|
Loading…
Reference in New Issue
Block a user