mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-22 01:30:51 +00:00
dbms: Set: removed special case for small sets (not worth in most cases) [#METR-2944].
This commit is contained in:
parent
0c14504781
commit
ab0e29f0f2
@ -12,7 +12,6 @@
|
||||
#include <DB/Parsers/IAST.h>
|
||||
|
||||
#include <DB/Common/HashTable/HashSet.h>
|
||||
#include <DB/Common/HashTable/SmallTable.h>
|
||||
#include <DB/Interpreters/AggregationCommon.h>
|
||||
#include <DB/Interpreters/Limits.h>
|
||||
#include <DB/Columns/ColumnConst.h>
|
||||
@ -29,13 +28,6 @@ namespace DB
|
||||
* Используются в качестве параметра шаблона.
|
||||
*/
|
||||
|
||||
template <typename Src, typename Dst>
|
||||
void copyHashTable(const Src & src, Dst & dst)
|
||||
{
|
||||
for (const auto & x : src)
|
||||
dst.insert(x);
|
||||
}
|
||||
|
||||
|
||||
/// Для случая, когда есть один числовой ключ.
|
||||
template <typename FieldType, typename TData> /// UInt8/16/32/64 для любых типов соответствующей битности.
|
||||
@ -46,11 +38,6 @@ struct SetMethodOneNumber
|
||||
|
||||
Data data;
|
||||
|
||||
SetMethodOneNumber() {}
|
||||
|
||||
template <typename Other>
|
||||
SetMethodOneNumber(const Other & other) { copyHashTable(other.data, data); }
|
||||
|
||||
/// Для использования одного Method в разных потоках, используйте разные State.
|
||||
struct State
|
||||
{
|
||||
@ -90,11 +77,6 @@ struct SetMethodString
|
||||
|
||||
Data data;
|
||||
|
||||
SetMethodString() {}
|
||||
|
||||
template <typename Other>
|
||||
SetMethodString(const Other & other) { copyHashTable(other.data, data); }
|
||||
|
||||
struct State
|
||||
{
|
||||
const ColumnString::Offsets_t * offsets;
|
||||
@ -136,11 +118,6 @@ struct SetMethodFixedString
|
||||
|
||||
Data data;
|
||||
|
||||
SetMethodFixedString() {}
|
||||
|
||||
template <typename Other>
|
||||
SetMethodFixedString(const Other & other) { copyHashTable(other.data, data); }
|
||||
|
||||
struct State
|
||||
{
|
||||
size_t n;
|
||||
@ -180,11 +157,6 @@ struct SetMethodKeysFixed
|
||||
|
||||
Data data;
|
||||
|
||||
SetMethodKeysFixed() {}
|
||||
|
||||
template <typename Other>
|
||||
SetMethodKeysFixed(const Other & other) { copyHashTable(other.data, data); }
|
||||
|
||||
struct State
|
||||
{
|
||||
void init(const ConstColumnPlainPtrs & key_columns)
|
||||
@ -214,11 +186,6 @@ struct SetMethodHashed
|
||||
|
||||
Data data;
|
||||
|
||||
SetMethodHashed() {}
|
||||
|
||||
template <typename Other>
|
||||
SetMethodHashed(const Other & other) { copyHashTable(other.data, data); }
|
||||
|
||||
struct State
|
||||
{
|
||||
void init(const ConstColumnPlainPtrs & key_columns)
|
||||
@ -248,6 +215,10 @@ struct SetVariants
|
||||
std::unique_ptr<SetMethodOneNumber<UInt8, HashSet<UInt8, TrivialHash, HashTableFixedGrower<8>>>> key8;
|
||||
std::unique_ptr<SetMethodOneNumber<UInt16, HashSet<UInt16, TrivialHash, HashTableFixedGrower<16>>>> key16;
|
||||
|
||||
/** Также для эксперимента проверялась возможность использовать SmallSet,
|
||||
* пока количество элементов в множестве небольшое (и, при необходимости, конвертировать в полноценный HashSet).
|
||||
* Но этот эксперимент показал, что преимущество есть только в редких случаях.
|
||||
*/
|
||||
std::unique_ptr<SetMethodOneNumber<UInt32, HashSet<UInt32, HashCRC32<UInt32>>>> key32;
|
||||
std::unique_ptr<SetMethodOneNumber<UInt64, HashSet<UInt64, HashCRC32<UInt64>>>> key64;
|
||||
std::unique_ptr<SetMethodString<HashSetWithSavedHash<StringRef>>> key_string;
|
||||
@ -256,35 +227,16 @@ struct SetVariants
|
||||
std::unique_ptr<SetMethodKeysFixed<HashSet<UInt256, UInt256HashCRC32>>> keys256;
|
||||
std::unique_ptr<SetMethodHashed<HashSet<UInt128, UInt128TrivialHash>>> hashed;
|
||||
|
||||
std::unique_ptr<SetMethodOneNumber<UInt32, SmallSet<UInt32, 16>>> key32_small;
|
||||
std::unique_ptr<SetMethodOneNumber<UInt64, SmallSet<UInt64, 16>>> key64_small;
|
||||
std::unique_ptr<SetMethodString<SmallSet<StringRef, 16>>> key_string_small;
|
||||
std::unique_ptr<SetMethodFixedString<SmallSet<StringRef, 16>>> key_fixed_string_small;
|
||||
std::unique_ptr<SetMethodKeysFixed<SmallSet<UInt128, 16>>> keys128_small;
|
||||
std::unique_ptr<SetMethodKeysFixed<SmallSet<UInt256, 16>>> keys256_small;
|
||||
std::unique_ptr<SetMethodHashed<SmallSet<UInt128, 16>>> hashed_small;
|
||||
/** В отличие от Aggregator, здесь не используется метод concat.
|
||||
* Это сделано потому что метод hashed, хоть и медленнее, но в данном случае, использует меньше оперативки.
|
||||
* так как при его использовании, сами значения ключей не сохраняются.
|
||||
*/
|
||||
|
||||
Arena string_pool;
|
||||
|
||||
#define APPLY_FOR_SET_VARIANTS(M) \
|
||||
M(key8, false) \
|
||||
M(key16, false) \
|
||||
M(key32, false) \
|
||||
M(key64, false) \
|
||||
M(key_string, false) \
|
||||
M(key_fixed_string, false) \
|
||||
M(keys128, false) \
|
||||
M(keys256, false) \
|
||||
M(hashed, false) \
|
||||
M(key32_small, true) \
|
||||
M(key64_small, true) \
|
||||
M(key_string_small, true) \
|
||||
M(key_fixed_string_small, true) \
|
||||
M(keys128_small, true) \
|
||||
M(keys256_small, true) \
|
||||
M(hashed_small, true)
|
||||
|
||||
#define APPLY_FOR_SET_VARIANTS_BIG(M) \
|
||||
M(key8) \
|
||||
M(key16) \
|
||||
M(key32) \
|
||||
M(key64) \
|
||||
M(key_string) \
|
||||
@ -297,7 +249,7 @@ struct SetVariants
|
||||
{
|
||||
EMPTY,
|
||||
|
||||
#define M(NAME, IS_SMALL) NAME,
|
||||
#define M(NAME) NAME,
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
#undef M
|
||||
};
|
||||
@ -313,9 +265,6 @@ struct SetVariants
|
||||
size_t getTotalRowCount() const;
|
||||
/// Считает размер в байтах буфера Set и размер string_pool'а
|
||||
size_t getTotalByteCount() const;
|
||||
|
||||
bool isSmall() const;
|
||||
void convertToBig();
|
||||
};
|
||||
|
||||
|
||||
@ -414,19 +363,9 @@ private:
|
||||
|
||||
|
||||
template <typename Method>
|
||||
size_t insertFromBlockImplBig(
|
||||
void insertFromBlockImpl(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & key_columns,
|
||||
size_t start,
|
||||
size_t rows,
|
||||
StringRefs & keys,
|
||||
SetVariants & variants);
|
||||
|
||||
template <typename Method>
|
||||
size_t insertFromBlockImplSmall(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & key_columns,
|
||||
size_t start,
|
||||
size_t rows,
|
||||
StringRefs & keys,
|
||||
SetVariants & variants);
|
||||
|
@ -29,7 +29,7 @@ void SetVariants::init(Type type_)
|
||||
{
|
||||
case Type::EMPTY: break;
|
||||
|
||||
#define M(NAME, IS_SMALL) \
|
||||
#define M(NAME) \
|
||||
case Type::NAME: NAME.reset(new decltype(NAME)::element_type); break;
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
#undef M
|
||||
@ -46,7 +46,7 @@ size_t SetVariants::getTotalRowCount() const
|
||||
{
|
||||
case Type::EMPTY: return 0;
|
||||
|
||||
#define M(NAME, IS_SMALL) \
|
||||
#define M(NAME) \
|
||||
case Type::NAME: return NAME->data.size();
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
#undef M
|
||||
@ -63,7 +63,7 @@ size_t SetVariants::getTotalByteCount() const
|
||||
{
|
||||
case Type::EMPTY: return 0;
|
||||
|
||||
#define M(NAME, IS_SMALL) \
|
||||
#define M(NAME) \
|
||||
case Type::NAME: return NAME->data.getBufferSizeInBytes();
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
#undef M
|
||||
@ -74,42 +74,6 @@ size_t SetVariants::getTotalByteCount() const
|
||||
}
|
||||
|
||||
|
||||
bool SetVariants::isSmall() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Type::EMPTY: return false;
|
||||
|
||||
#define M(NAME, IS_SMALL) \
|
||||
case Type::NAME: return IS_SMALL;
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
#undef M
|
||||
|
||||
default:
|
||||
throw Exception("Unknown Set variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetVariants::convertToBig()
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#define M(NAME) \
|
||||
case Type::NAME ## _small: \
|
||||
NAME.reset(new decltype(NAME)::element_type(*NAME ## _small)); \
|
||||
NAME ## _small.reset(); \
|
||||
type = Type::NAME; \
|
||||
break;
|
||||
APPLY_FOR_SET_VARIANTS_BIG(M)
|
||||
#undef M
|
||||
|
||||
default:
|
||||
throw Exception("Unknown Set variant.", ErrorCodes::UNKNOWN_AGGREGATED_DATA_VARIANT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Set::checkSetSizeLimits() const
|
||||
{
|
||||
if (max_rows && data.getTotalRowCount() > max_rows)
|
||||
@ -122,9 +86,6 @@ bool Set::checkSetSizeLimits() const
|
||||
|
||||
SetVariants::Type SetVariants::chooseMethod(const ConstColumnPlainPtrs & key_columns, Sizes & key_sizes)
|
||||
{
|
||||
/** Возвращает small-методы, так как обработка начинается с них.
|
||||
* Затем, в процессе работы, данные могут быть переконвертированы в полноценную (не small) структуру, если их становится много.
|
||||
*/
|
||||
size_t keys_size = key_columns.size();
|
||||
|
||||
bool all_fixed = true;
|
||||
@ -150,35 +111,34 @@ SetVariants::Type SetVariants::chooseMethod(const ConstColumnPlainPtrs & key_col
|
||||
if (size_of_field == 2)
|
||||
return SetVariants::Type::key16;
|
||||
if (size_of_field == 4)
|
||||
return SetVariants::Type::key32_small;
|
||||
return SetVariants::Type::key32;
|
||||
if (size_of_field == 8)
|
||||
return SetVariants::Type::key64_small;
|
||||
return SetVariants::Type::key64;
|
||||
throw Exception("Logical error: numeric column has sizeOfField not in 1, 2, 4, 8.", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
/// Если ключи помещаются в N бит, будем использовать хэш-таблицу по упакованным в N-бит ключам
|
||||
if (all_fixed && keys_bytes <= 16)
|
||||
return SetVariants::Type::keys128_small;
|
||||
return SetVariants::Type::keys128;
|
||||
if (all_fixed && keys_bytes <= 32)
|
||||
return SetVariants::Type::keys256_small;
|
||||
return SetVariants::Type::keys256;
|
||||
|
||||
/// Если есть один строковый ключ, то используем хэш-таблицу с ним
|
||||
if (keys_size == 1 && (typeid_cast<const ColumnString *>(key_columns[0]) || typeid_cast<const ColumnConstString *>(key_columns[0])))
|
||||
return SetVariants::Type::key_string_small;
|
||||
return SetVariants::Type::key_string;
|
||||
|
||||
if (keys_size == 1 && typeid_cast<const ColumnFixedString *>(key_columns[0]))
|
||||
return SetVariants::Type::key_fixed_string_small;
|
||||
return SetVariants::Type::key_fixed_string;
|
||||
|
||||
/// Иначе будем агрегировать по конкатенации ключей.
|
||||
return SetVariants::Type::hashed_small;
|
||||
return SetVariants::Type::hashed;
|
||||
}
|
||||
|
||||
|
||||
template <typename Method>
|
||||
size_t NO_INLINE Set::insertFromBlockImplSmall(
|
||||
void NO_INLINE Set::insertFromBlockImpl(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & key_columns,
|
||||
size_t start,
|
||||
size_t rows,
|
||||
StringRefs & keys,
|
||||
SetVariants & variants)
|
||||
@ -188,38 +148,7 @@ size_t NO_INLINE Set::insertFromBlockImplSmall(
|
||||
size_t keys_size = key_columns.size();
|
||||
|
||||
/// Для всех строчек
|
||||
for (size_t i = start; i < rows; ++i)
|
||||
{
|
||||
/// Строим ключ
|
||||
typename Method::Key key = state.getKey(key_columns, keys_size, i, key_sizes, keys);
|
||||
|
||||
typename Method::Data::iterator it = method.data.find(key);
|
||||
bool inserted;
|
||||
if (!method.data.tryEmplace(key, it, inserted))
|
||||
return i;
|
||||
|
||||
if (inserted)
|
||||
method.onNewKey(*it, keys_size, i, keys, variants.string_pool);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
size_t NO_INLINE Set::insertFromBlockImplBig(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & key_columns,
|
||||
size_t start,
|
||||
size_t rows,
|
||||
StringRefs & keys,
|
||||
SetVariants & variants)
|
||||
{
|
||||
typename Method::State state;
|
||||
state.init(key_columns);
|
||||
size_t keys_size = key_columns.size();
|
||||
|
||||
/// Для всех строчек
|
||||
for (size_t i = start; i < rows; ++i)
|
||||
for (size_t i = 0; i < rows; ++i)
|
||||
{
|
||||
/// Строим ключ
|
||||
typename Method::Key key = state.getKey(key_columns, keys_size, i, key_sizes, keys);
|
||||
@ -231,8 +160,6 @@ size_t NO_INLINE Set::insertFromBlockImplBig(
|
||||
if (inserted)
|
||||
method.onNewKey(*it, keys_size, i, keys, variants.string_pool);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
@ -258,54 +185,19 @@ bool Set::insertFromBlock(const Block & block, bool create_ordered_set)
|
||||
data.init(data.chooseMethod(key_columns, key_sizes));
|
||||
|
||||
StringRefs keys;
|
||||
size_t start = 0;
|
||||
|
||||
if (false) {}
|
||||
else if (data.type == SetVariants::Type::key8)
|
||||
start = insertFromBlockImplBig(*data.key8, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key16)
|
||||
start = insertFromBlockImplBig(*data.key16, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key32_small)
|
||||
start = insertFromBlockImplSmall(*data.key32_small, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key64_small)
|
||||
start = insertFromBlockImplSmall(*data.key64_small, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key_string_small)
|
||||
start = insertFromBlockImplSmall(*data.key_string_small, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key_fixed_string_small)
|
||||
start = insertFromBlockImplSmall(*data.key_fixed_string_small, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::keys128_small)
|
||||
start = insertFromBlockImplSmall(*data.keys128_small, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::keys256_small)
|
||||
start = insertFromBlockImplSmall(*data.keys256_small, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::hashed_small)
|
||||
start = insertFromBlockImplSmall(*data.hashed_small, key_columns, start, rows, keys, data);
|
||||
|
||||
/// Нужно ли сконвертировать из small в полноценный вариант.
|
||||
if (data.isSmall() && start != rows)
|
||||
data.convertToBig();
|
||||
|
||||
if (false) {}
|
||||
else if (data.type == SetVariants::Type::key32)
|
||||
start = insertFromBlockImplBig(*data.key32, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key64)
|
||||
start = insertFromBlockImplBig(*data.key64, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key_string)
|
||||
start = insertFromBlockImplBig(*data.key_string, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::key_fixed_string)
|
||||
start = insertFromBlockImplBig(*data.key_fixed_string, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::keys128)
|
||||
start = insertFromBlockImplBig(*data.keys128, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::keys256)
|
||||
start = insertFromBlockImplBig(*data.keys256, key_columns, start, rows, keys, data);
|
||||
else if (data.type == SetVariants::Type::hashed)
|
||||
start = insertFromBlockImplBig(*data.hashed, key_columns, start, rows, keys, data);
|
||||
|
||||
if (start == 0)
|
||||
#define M(NAME) \
|
||||
else if (data.type == SetVariants::Type::NAME) \
|
||||
insertFromBlockImpl(*data.NAME, key_columns, rows, keys, data);
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
#undef M
|
||||
else
|
||||
throw Exception("Unknown set variant.", ErrorCodes::UNKNOWN_SET_DATA_VARIANT);
|
||||
|
||||
if (create_ordered_set)
|
||||
for (size_t i = 0; i < rows; ++i)
|
||||
ordered_set_elements->push_back((*key_columns[0])[i]);
|
||||
ordered_set_elements->push_back((*key_columns[0])[i]); /// ordered_set для индекса работает только если IN одному ключу.
|
||||
|
||||
if (!checkSetSizeLimits())
|
||||
{
|
||||
@ -637,7 +529,7 @@ void Set::executeOrdinary(const ConstColumnPlainPtrs & key_columns, ColumnUInt8:
|
||||
StringRefs keys;
|
||||
|
||||
if (false) {}
|
||||
#define M(NAME, IS_SMALL) \
|
||||
#define M(NAME) \
|
||||
else if (data.type == SetVariants::Type::NAME) \
|
||||
executeImpl(*data.NAME, key_columns, vec_res, negative, rows, keys);
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
@ -654,7 +546,7 @@ void Set::executeArray(const ColumnArray * key_column, ColumnUInt8::Container_t
|
||||
StringRefs keys;
|
||||
|
||||
if (false) {}
|
||||
#define M(NAME, IS_SMALL) \
|
||||
#define M(NAME) \
|
||||
else if (data.type == SetVariants::Type::NAME) \
|
||||
executeArrayImpl(*data.NAME, ConstColumnPlainPtrs{key_column}, offsets, vec_res, negative, rows, keys);
|
||||
APPLY_FOR_SET_VARIANTS(M)
|
||||
|
Loading…
Reference in New Issue
Block a user