2014-06-12 02:31:30 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <statdaemons/Stopwatch.h>
|
|
|
|
|
|
|
|
|
|
#include <Yandex/logger_useful.h>
|
|
|
|
|
|
2014-06-18 18:31:35 +00:00
|
|
|
|
#include <DB/Parsers/ASTJoin.h>
|
|
|
|
|
|
2014-06-12 02:31:30 +00:00
|
|
|
|
#include <DB/Interpreters/AggregationCommon.h>
|
|
|
|
|
#include <DB/Interpreters/Set.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/Common/Arena.h>
|
|
|
|
|
#include <DB/Common/HashTable/HashMap.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/DataStreams/IBlockInputStream.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Структура данных для реализации JOIN-а.
|
|
|
|
|
* По сути, хэш-таблица: ключи -> строки присоединяемой таблицы.
|
2014-06-19 19:00:58 +00:00
|
|
|
|
*
|
|
|
|
|
* JOIN-ы бывают четырёх типов: ANY/ALL x LEFT/INNER.
|
|
|
|
|
*
|
|
|
|
|
* Если указано ANY - выбрать из "правой" таблицы только одну, первую попавшуюся строку, даже если там более одной соответствующей строки.
|
|
|
|
|
* Если указано ALL - обычный вариант JOIN-а, при котором строки могут размножаться по числу соответствующих строк "правой" таблицы.
|
|
|
|
|
* Вариант ANY работает более оптимально.
|
|
|
|
|
*
|
|
|
|
|
* Если указано INNER - оставить только строки, для которых есть хотя бы одна строка "правой" таблицы.
|
|
|
|
|
* Если указано LEFT - в случае, если в "правой" таблице нет соответствующей строки, заполнить её значениями "по-умолчанию".
|
|
|
|
|
*
|
|
|
|
|
* Все соединения делаются по равенству кортежа столбцов "ключей" (эквисоединение).
|
|
|
|
|
* Неравенства и прочие условия не поддерживаются.
|
|
|
|
|
*
|
|
|
|
|
* Реализация такая:
|
|
|
|
|
*
|
|
|
|
|
* 1. "Правая" таблица засовывается в хэш-таблицу в оперативке.
|
|
|
|
|
* Она имеет вид keys -> row в случае ANY или keys -> [rows...] в случае ALL.
|
|
|
|
|
* Это делается в функции insertFromBlock.
|
|
|
|
|
*
|
|
|
|
|
* 2. При обработке "левой" таблицы, присоединяем к ней данные из сформированной хэш-таблицы.
|
|
|
|
|
* Это делается в функции joinBlock.
|
|
|
|
|
*
|
|
|
|
|
* В случае ANY LEFT JOIN - формируем новые столбцы с найденной строкой или значениями по-умолчанию.
|
|
|
|
|
* Самый простой вариант. Количество строк при JOIN-е не меняется.
|
|
|
|
|
*
|
|
|
|
|
* В случае ANY INNER JOIN - формируем новые столбцы с найденной строкой;
|
|
|
|
|
* а также заполняем фильтр - для каких строк значения не нашлось.
|
|
|
|
|
* После чего, фильтруем столбцы "левой" таблицы.
|
|
|
|
|
*
|
|
|
|
|
* В случае ALL ... JOIN - формируем новые столбцы со всеми найденными строками;
|
|
|
|
|
* а также заполняем массив offsets, описывающий, во сколько раз надо размножить строки "левой" таблицы.
|
|
|
|
|
* После чего, размножаем столбцы "левой" таблицы.
|
2014-06-12 02:31:30 +00:00
|
|
|
|
*/
|
|
|
|
|
class Join
|
|
|
|
|
{
|
|
|
|
|
public:
|
2014-07-02 20:23:48 +00:00
|
|
|
|
Join(const Names & key_names_left_, const Names & key_names_right_,
|
|
|
|
|
const Limits & limits, ASTJoin::Kind kind_, ASTJoin::Strictness strictness_)
|
2014-06-18 18:31:35 +00:00
|
|
|
|
: kind(kind_), strictness(strictness_),
|
2014-07-02 20:23:48 +00:00
|
|
|
|
key_names_left(key_names_left_),
|
|
|
|
|
key_names_right(key_names_right_),
|
2014-06-12 02:31:30 +00:00
|
|
|
|
log(&Logger::get("Join")),
|
|
|
|
|
max_rows(limits.max_rows_in_set),
|
|
|
|
|
max_bytes(limits.max_bytes_in_set),
|
|
|
|
|
overflow_mode(limits.set_overflow_mode)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
bool empty() { return type == Set::EMPTY; }
|
2014-06-12 02:31:30 +00:00
|
|
|
|
|
2014-06-12 04:04:47 +00:00
|
|
|
|
/** Добавить в отображение для соединения блок "правой" таблицы.
|
|
|
|
|
* Возвращает false, если превышено какое-нибудь ограничение, и больше не нужно вставлять.
|
|
|
|
|
*/
|
|
|
|
|
bool insertFromBlock(const Block & block);
|
|
|
|
|
|
|
|
|
|
/** Присоединить к блоку "левой" таблицы новые столбцы из сформированного отображения.
|
|
|
|
|
*/
|
2014-06-18 18:31:35 +00:00
|
|
|
|
void joinBlock(Block & block);
|
2014-06-12 02:31:30 +00:00
|
|
|
|
|
|
|
|
|
size_t size() const { return getTotalRowCount(); }
|
2014-06-18 18:31:35 +00:00
|
|
|
|
|
2014-06-12 02:31:30 +00:00
|
|
|
|
|
|
|
|
|
/// Ссылка на строку в блоке.
|
|
|
|
|
struct RowRef
|
|
|
|
|
{
|
|
|
|
|
const Block * block;
|
|
|
|
|
size_t row_num;
|
|
|
|
|
|
|
|
|
|
RowRef() {}
|
|
|
|
|
RowRef(const Block * block_, size_t row_num_) : block(block_), row_num(row_num_) {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Односвязный список ссылок на строки.
|
|
|
|
|
struct RowRefList : RowRef
|
|
|
|
|
{
|
|
|
|
|
RowRefList * next = nullptr;
|
|
|
|
|
|
|
|
|
|
RowRefList() {}
|
|
|
|
|
RowRefList(const Block * block_, size_t row_num_) : RowRef(block_, row_num_) {}
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-18 19:14:29 +00:00
|
|
|
|
/** Разные структуры данных, которые могут использоваться для соединения.
|
|
|
|
|
*/
|
2014-06-18 20:08:31 +00:00
|
|
|
|
struct MapsAny
|
|
|
|
|
{
|
|
|
|
|
/// Специализация для случая, когда есть один числовой ключ.
|
|
|
|
|
typedef HashMap<UInt64, RowRef> MapUInt64;
|
|
|
|
|
|
|
|
|
|
/// Специализация для случая, когда есть один строковый ключ.
|
|
|
|
|
typedef HashMapWithSavedHash<StringRef, RowRef> MapString;
|
|
|
|
|
|
|
|
|
|
/** Сравнивает 128 битные хэши.
|
|
|
|
|
* Если все ключи фиксированной длины, влезающие целиком в 128 бит, то укладывает их без изменений в 128 бит.
|
|
|
|
|
* Иначе - вычисляет SipHash от набора из всех ключей.
|
|
|
|
|
* (При этом, строки, содержащие нули посередине, могут склеиться.)
|
|
|
|
|
*/
|
|
|
|
|
typedef HashMap<UInt128, RowRef, UInt128Hash> MapHashed;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<MapUInt64> key64;
|
|
|
|
|
std::unique_ptr<MapString> key_string;
|
|
|
|
|
std::unique_ptr<MapHashed> hashed;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct MapsAll
|
|
|
|
|
{
|
|
|
|
|
typedef HashMap<UInt64, RowRefList> MapUInt64;
|
|
|
|
|
typedef HashMapWithSavedHash<StringRef, RowRefList> MapString;
|
|
|
|
|
typedef HashMap<UInt128, RowRefList, UInt128Hash> MapHashed;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<MapUInt64> key64;
|
|
|
|
|
std::unique_ptr<MapString> key_string;
|
|
|
|
|
std::unique_ptr<MapHashed> hashed;
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-18 19:14:29 +00:00
|
|
|
|
private:
|
|
|
|
|
ASTJoin::Kind kind;
|
|
|
|
|
ASTJoin::Strictness strictness;
|
|
|
|
|
|
2014-07-02 20:23:48 +00:00
|
|
|
|
/// Имена и номера ключевых столбцов (по которым производится соединение) в "левой" таблице.
|
|
|
|
|
const Names key_names_left;
|
2014-06-18 19:14:29 +00:00
|
|
|
|
ColumnNumbers key_numbers_left;
|
2014-07-02 20:23:48 +00:00
|
|
|
|
/// Имена и номера ключевых столбцов (по которым производится соединение) в "правой" таблице.
|
|
|
|
|
const Names key_names_right;
|
2014-06-18 19:14:29 +00:00
|
|
|
|
ColumnNumbers key_numbers_right;
|
|
|
|
|
|
2014-06-12 02:31:30 +00:00
|
|
|
|
/** Блоки данных таблицы, с которой идёт соединение.
|
|
|
|
|
*/
|
|
|
|
|
Blocks blocks;
|
|
|
|
|
|
2014-06-18 20:08:31 +00:00
|
|
|
|
MapsAny maps_any;
|
|
|
|
|
MapsAll maps_all;
|
2014-06-12 02:31:30 +00:00
|
|
|
|
|
|
|
|
|
/// Дополнительные данные - строки, а также продолжения односвязных списков строк.
|
|
|
|
|
Arena pool;
|
|
|
|
|
|
|
|
|
|
Set::Type type = Set::EMPTY;
|
2014-07-06 19:48:39 +00:00
|
|
|
|
|
2014-06-12 02:31:30 +00:00
|
|
|
|
bool keys_fit_128_bits;
|
|
|
|
|
Sizes key_sizes;
|
|
|
|
|
|
|
|
|
|
Logger * log;
|
2014-07-06 19:48:39 +00:00
|
|
|
|
|
2014-06-12 02:31:30 +00:00
|
|
|
|
/// Ограничения на максимальный размер множества
|
|
|
|
|
size_t max_rows;
|
|
|
|
|
size_t max_bytes;
|
|
|
|
|
OverflowMode overflow_mode;
|
|
|
|
|
|
2014-06-18 20:08:31 +00:00
|
|
|
|
void init(Set::Type type_);
|
|
|
|
|
|
|
|
|
|
template <ASTJoin::Strictness STRICTNESS, typename Maps>
|
|
|
|
|
void insertFromBlockImpl(Maps & maps, size_t rows, const ConstColumnPlainPtrs & key_columns, size_t keys_size, Block * stored_block);
|
2014-06-12 02:31:30 +00:00
|
|
|
|
|
2014-06-19 18:15:46 +00:00
|
|
|
|
template <ASTJoin::Kind KIND, ASTJoin::Strictness STRICTNESS, typename Maps>
|
|
|
|
|
void joinBlockImpl(Block & block, Maps & maps);
|
2014-06-18 18:31:35 +00:00
|
|
|
|
|
2014-06-12 02:31:30 +00:00
|
|
|
|
/// Проверить не превышены ли допустимые размеры множества
|
|
|
|
|
bool checkSizeLimits() const;
|
|
|
|
|
|
2014-07-06 19:48:39 +00:00
|
|
|
|
/// Считает суммарное число ключей во всех Join'ах
|
2014-06-12 02:31:30 +00:00
|
|
|
|
size_t getTotalRowCount() const;
|
2014-07-06 19:48:39 +00:00
|
|
|
|
/// Считает суммарный размер в байтах буфферов всех Join'ов + размер string_pool'а
|
2014-06-12 02:31:30 +00:00
|
|
|
|
size_t getTotalByteCount() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef Poco::SharedPtr<Join> JoinPtr;
|
|
|
|
|
typedef std::vector<JoinPtr> Joins;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|