mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge branch 'master' of github.com:ClickHouse/ClickHouse into parsing-constraints
This commit is contained in:
commit
070d1bcdd0
37
base/common/sort.h
Normal file
37
base/common/sort.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
# include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#else
|
||||
# include <algorithm>
|
||||
#endif
|
||||
|
||||
template <class RandomIt>
|
||||
void nth_element(RandomIt first, RandomIt nth, RandomIt last)
|
||||
{
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
::miniselect::floyd_rivest_select(first, nth, last);
|
||||
#else
|
||||
::std::nth_element(first, nth, last);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class RandomIt>
|
||||
void partial_sort(RandomIt first, RandomIt middle, RandomIt last)
|
||||
{
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
::miniselect::floyd_rivest_partial_sort(first, middle, last);
|
||||
#else
|
||||
::std::partial_sort(first, middle, last);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class RandomIt, class Compare>
|
||||
void partial_sort(RandomIt first, RandomIt middle, RandomIt last, Compare compare)
|
||||
{
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
::miniselect::floyd_rivest_partial_sort(first, middle, last, compare);
|
||||
#else
|
||||
::std::partial_sort(first, middle, last, compare);
|
||||
#endif
|
||||
}
|
@ -26,6 +26,9 @@ toc_title: Client Libraries
|
||||
- [go-clickhouse](https://github.com/roistat/go-clickhouse)
|
||||
- [mailrugo-clickhouse](https://github.com/mailru/go-clickhouse)
|
||||
- [golang-clickhouse](https://github.com/leprosus/golang-clickhouse)
|
||||
- Swift
|
||||
- [ClickHouseNIO](https://github.com/patrick-zippenfenig/ClickHouseNIO)
|
||||
- [ClickHouseVapor ORM](https://github.com/patrick-zippenfenig/ClickHouseVapor)
|
||||
- NodeJs
|
||||
- [clickhouse (NodeJs)](https://github.com/TimonKK/clickhouse)
|
||||
- [node-clickhouse](https://github.com/apla/node-clickhouse)
|
||||
|
@ -1081,4 +1081,45 @@ Default value: `/var/lib/clickhouse/access/`.
|
||||
|
||||
- [Access Control and Account Management](../../operations/access-rights.md#access-control)
|
||||
|
||||
## user_directories {#user_directories}
|
||||
|
||||
Section of the configuration file that contains settings:
|
||||
- Path to configuration file with predefined users.
|
||||
- Path to folder where users created by SQL commands are stored.
|
||||
|
||||
If this section is specified, the path from [users_config](../../operations/server-configuration-parameters/settings.md#users-config) and [access_control_path](../../operations/server-configuration-parameters/settings.md#access_control_path) won't be used.
|
||||
|
||||
The `user_directories` section can contain any number of items, the order of the items means their precedence (the higher the item the higher the precedence).
|
||||
|
||||
**Example**
|
||||
|
||||
``` xml
|
||||
<user_directories>
|
||||
<users_xml>
|
||||
<path>/etc/clickhouse-server/users.xml</path>
|
||||
</users_xml>
|
||||
<local_directory>
|
||||
<path>/var/lib/clickhouse/access/</path>
|
||||
</local_directory>
|
||||
</user_directories>
|
||||
```
|
||||
|
||||
You can also specify settings `memory` — means storing information only in memory, without writing to disk, and `ldap` — means storing information on an LDAP server.
|
||||
|
||||
To add an LDAP server as a remote user directory of users that are not defined locally, define a single `ldap` section with a following parameters:
|
||||
- `server` — one of LDAP server names defined in `ldap_servers` config section. This parameter is mandatory and cannot be empty.
|
||||
- `roles` — section with a list of locally defined roles that will be assigned to each user retrieved from the LDAP server. If no roles are specified, user will not be able to perform any actions after authentication. If any of the listed roles is not defined locally at the time of authentication, the authenthication attept will fail as if the provided password was incorrect.
|
||||
|
||||
**Example**
|
||||
|
||||
``` xml
|
||||
<ldap>
|
||||
<server>my_ldap_server</server>
|
||||
<roles>
|
||||
<my_local_role1 />
|
||||
<my_local_role2 />
|
||||
</roles>
|
||||
</ldap>
|
||||
```
|
||||
|
||||
[Original article](https://clickhouse.tech/docs/en/operations/server_configuration_parameters/settings/) <!--hide-->
|
||||
|
@ -204,7 +204,7 @@ SYSTEM STOP MOVES [[db.]merge_tree_family_table_name]
|
||||
|
||||
## Managing ReplicatedMergeTree Tables {#query-language-system-replicated}
|
||||
|
||||
ClickHouse can manage background replication related processes in [ReplicatedMergeTree](../../engines/table-engines/mergetree-family/replacingmergetree.md) tables.
|
||||
ClickHouse can manage background replication related processes in [ReplicatedMergeTree](../../engines/table-engines/mergetree-family/replication/#table_engines-replication) tables.
|
||||
|
||||
### STOP FETCHES {#query_language-system-stop-fetches}
|
||||
|
||||
|
@ -57,7 +57,7 @@ Identifiers are:
|
||||
|
||||
Identifiers can be quoted or non-quoted. The latter is preferred.
|
||||
|
||||
Non-quoted identifiers must match the regex `^[a-zA-Z_][0-9a-zA-Z_]*$` and can not be equal to [keywords](#syntax-keywords). Examples: `x, _1, X_y__Z123_.`
|
||||
Non-quoted identifiers must match the regex `^[0-9a-zA-Z_]*[a-zA-Z_]$` and can not be equal to [keywords](#syntax-keywords). Examples: `x, _1, X_y__Z123_.`
|
||||
|
||||
If you want to use identifiers the same as keywords or you want to use other symbols in identifiers, quote it using double quotes or backticks, for example, `"id"`, `` `id` ``.
|
||||
|
||||
|
@ -1068,4 +1068,45 @@ ClickHouse использует ZooKeeper для хранения метадан
|
||||
|
||||
- [Управление доступом](../access-rights.md#access-control)
|
||||
|
||||
## user_directories {#user_directories}
|
||||
|
||||
Секция конфигурационного файла,которая содержит настройки:
|
||||
- Путь к конфигурационному файлу с предустановленными пользователями.
|
||||
- Путь к файлу, в котором содержатся пользователи, созданные при помощи SQL команд.
|
||||
|
||||
Если эта секция определена, путь из [users_config](../../operations/server-configuration-parameters/settings.md#users-config) и [access_control_path](../../operations/server-configuration-parameters/settings.md#access_control_path) не используется.
|
||||
|
||||
Секция `user_directories` может содержать любое количество элементов, порядок расположения элементов обозначает их приоритет (чем выше элемент, тем выше приоритет).
|
||||
|
||||
**Пример**
|
||||
|
||||
``` xml
|
||||
<user_directories>
|
||||
<users_xml>
|
||||
<path>/etc/clickhouse-server/users.xml</path>
|
||||
</users_xml>
|
||||
<local_directory>
|
||||
<path>/var/lib/clickhouse/access/</path>
|
||||
</local_directory>
|
||||
</user_directories>
|
||||
```
|
||||
|
||||
Также вы можете указать настройку `memory` — означает хранение информации только в памяти, без записи на диск, и `ldap` — означает хранения информации на [LDAP-сервере](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol).
|
||||
|
||||
Чтобы добавить LDAP-сервер в качестве удаленного каталога пользователей, которые не определены локально, определите один раздел `ldap` со следующими параметрами:
|
||||
- `server` — имя одного из LDAP-серверов, определенных в секции `ldap_servers` конфигурациионного файла. Этот параметр явялется необязательным и может быть пустым.
|
||||
- `roles` — раздел со списком локально определенных ролей, которые будут назначены каждому пользователю, полученному с LDAP-сервера. Если роли не заданы, пользователь не сможет выполнять никаких действий после аутентификации. Если какая-либо из перечисленных ролей не определена локально во время проверки подлинности, попытка проверки подлинности завершится неудачей, как если бы предоставленный пароль был неверным.
|
||||
|
||||
**Пример**
|
||||
|
||||
``` xml
|
||||
<ldap>
|
||||
<server>my_ldap_server</server>
|
||||
<roles>
|
||||
<my_local_role1 />
|
||||
<my_local_role2 />
|
||||
</roles>
|
||||
</ldap>
|
||||
```
|
||||
|
||||
[Оригинальная статья](https://clickhouse.tech/docs/ru/operations/server_configuration_parameters/settings/) <!--hide-->
|
||||
|
@ -680,7 +680,7 @@ void updateSnapshot(Snapshot & snapshot, const Commit & commit, CommitDiff & fil
|
||||
for (auto & elem : file_changes)
|
||||
{
|
||||
auto & file = elem.second.file_change;
|
||||
if (file.path != file.old_path)
|
||||
if (!file.old_path.empty() && file.path != file.old_path)
|
||||
snapshot[file.path] = snapshot[file.old_path];
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <common/types.h>
|
||||
#include <IO/ReadBuffer.h>
|
||||
#include <IO/VarInt.h>
|
||||
#include <IO/WriteBuffer.h>
|
||||
#include <Common/NaNUtils.h>
|
||||
#include <Common/PODArray.h>
|
||||
#include <common/sort.h>
|
||||
#include <common/types.h>
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NOT_IMPLEMENTED;
|
||||
@ -89,12 +87,7 @@ struct QuantileExact : QuantileExactBase<Value, QuantileExact<Value>>
|
||||
if (!array.empty())
|
||||
{
|
||||
size_t n = level < 1 ? level * array.size() : (array.size() - 1);
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin(), array.begin() + n, array.end()); /// NOTE You can think of the radix-select algorithm.
|
||||
#else
|
||||
std::nth_element(array.begin(), array.begin() + n, array.end()); /// NOTE You can think of the radix-select algorithm.
|
||||
#endif
|
||||
nth_element(array.begin(), array.begin() + n, array.end()); /// NOTE: You can think of the radix-select algorithm.
|
||||
return array[n];
|
||||
}
|
||||
|
||||
@ -113,12 +106,7 @@ struct QuantileExact : QuantileExactBase<Value, QuantileExact<Value>>
|
||||
auto level = levels[indices[i]];
|
||||
|
||||
size_t n = level < 1 ? level * array.size() : (array.size() - 1);
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin() + prev_n, array.begin() + n, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin() + prev_n, array.begin() + n, array.end());
|
||||
#endif
|
||||
nth_element(array.begin() + prev_n, array.begin() + n, array.end());
|
||||
result[indices[i]] = array[n];
|
||||
prev_n = n;
|
||||
}
|
||||
@ -154,14 +142,10 @@ struct QuantileExactExclusive : public QuantileExact<Value>
|
||||
else if (n < 1)
|
||||
return static_cast<Float64>(array[0]);
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin(), array.begin() + n - 1, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin(), array.begin() + n - 1, array.end());
|
||||
#endif
|
||||
auto nth_element = std::min_element(array.begin() + n, array.end());
|
||||
nth_element(array.begin(), array.begin() + n - 1, array.end());
|
||||
auto nth_elem = std::min_element(array.begin() + n, array.end());
|
||||
|
||||
return static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_element - array[n - 1]);
|
||||
return static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_elem - array[n - 1]);
|
||||
}
|
||||
|
||||
return std::numeric_limits<Float64>::quiet_NaN();
|
||||
@ -187,14 +171,10 @@ struct QuantileExactExclusive : public QuantileExact<Value>
|
||||
result[indices[i]] = static_cast<Float64>(array[0]);
|
||||
else
|
||||
{
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin() + prev_n, array.begin() + n - 1, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end());
|
||||
#endif
|
||||
auto nth_element = std::min_element(array.begin() + n, array.end());
|
||||
nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end());
|
||||
auto nth_elem = std::min_element(array.begin() + n, array.end());
|
||||
|
||||
result[indices[i]] = static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_element - array[n - 1]);
|
||||
result[indices[i]] = static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_elem - array[n - 1]);
|
||||
prev_n = n - 1;
|
||||
}
|
||||
}
|
||||
@ -226,14 +206,10 @@ struct QuantileExactInclusive : public QuantileExact<Value>
|
||||
return static_cast<Float64>(array[array.size() - 1]);
|
||||
else if (n < 1)
|
||||
return static_cast<Float64>(array[0]);
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin(), array.begin() + n - 1, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin(), array.begin() + n - 1, array.end());
|
||||
#endif
|
||||
auto nth_element = std::min_element(array.begin() + n, array.end());
|
||||
nth_element(array.begin(), array.begin() + n - 1, array.end());
|
||||
auto nth_elem = std::min_element(array.begin() + n, array.end());
|
||||
|
||||
return static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_element - array[n - 1]);
|
||||
return static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_elem - array[n - 1]);
|
||||
}
|
||||
|
||||
return std::numeric_limits<Float64>::quiet_NaN();
|
||||
@ -257,14 +233,10 @@ struct QuantileExactInclusive : public QuantileExact<Value>
|
||||
result[indices[i]] = static_cast<Float64>(array[0]);
|
||||
else
|
||||
{
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin() + prev_n, array.begin() + n - 1, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end());
|
||||
#endif
|
||||
auto nth_element = std::min_element(array.begin() + n, array.end());
|
||||
nth_element(array.begin() + prev_n, array.begin() + n - 1, array.end());
|
||||
auto nth_elem = std::min_element(array.begin() + n, array.end());
|
||||
|
||||
result[indices[i]] = static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_element - array[n - 1]);
|
||||
result[indices[i]] = static_cast<Float64>(array[n - 1]) + (h - n) * static_cast<Float64>(*nth_elem - array[n - 1]);
|
||||
prev_n = n - 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <IO/ReadBuffer.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteBuffer.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Common/PODArray.h>
|
||||
#include <IO/ReadBuffer.h>
|
||||
#include <IO/WriteBuffer.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <common/sort.h>
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -140,7 +138,7 @@ namespace detail
|
||||
using Array = PODArray<UInt16, 128>;
|
||||
mutable Array elems; /// mutable because array sorting is not considered a state change.
|
||||
|
||||
QuantileTimingMedium() {}
|
||||
QuantileTimingMedium() = default;
|
||||
QuantileTimingMedium(const UInt16 * begin, const UInt16 * end) : elems(begin, end) {}
|
||||
|
||||
void insert(UInt64 x)
|
||||
@ -182,11 +180,7 @@ namespace detail
|
||||
|
||||
/// Sorting an array will not be considered a violation of constancy.
|
||||
auto & array = elems;
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin(), array.begin() + n, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin(), array.begin() + n, array.end());
|
||||
#endif
|
||||
nth_element(array.begin(), array.begin() + n, array.end());
|
||||
quantile = array[n];
|
||||
}
|
||||
|
||||
@ -207,11 +201,7 @@ namespace detail
|
||||
? level * elems.size()
|
||||
: (elems.size() - 1);
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_select(array.begin() + prev_n, array.begin() + n, array.end());
|
||||
#else
|
||||
std::nth_element(array.begin() + prev_n, array.begin() + n, array.end());
|
||||
#endif
|
||||
nth_element(array.begin() + prev_n, array.begin() + n, array.end());
|
||||
|
||||
result[level_index] = array[n];
|
||||
prev_n = n;
|
||||
@ -282,7 +272,7 @@ namespace detail
|
||||
}
|
||||
|
||||
public:
|
||||
Iterator(const QuantileTimingLarge & parent)
|
||||
explicit Iterator(const QuantileTimingLarge & parent)
|
||||
: begin(parent.count_small), pos(begin), end(&parent.count_big[BIG_SIZE])
|
||||
{
|
||||
adjust();
|
||||
@ -429,8 +419,8 @@ namespace detail
|
||||
template <typename ResultType>
|
||||
void getMany(const double * levels, const size_t * indices, size_t size, ResultType * result) const
|
||||
{
|
||||
const auto indices_end = indices + size;
|
||||
auto index = indices;
|
||||
const auto * indices_end = indices + size;
|
||||
const auto * index = indices;
|
||||
|
||||
UInt64 pos = std::ceil(count * levels[*index]);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
|
||||
#include <common/unaligned.h>
|
||||
#include <common/sort.h>
|
||||
|
||||
#include <DataStreams/ColumnGathererStream.h>
|
||||
|
||||
@ -20,10 +21,6 @@
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -786,11 +783,7 @@ void ColumnArray::getPermutationImpl(size_t limit, Permutation & res, Comparator
|
||||
auto less = [&cmp](size_t lhs, size_t rhs){ return cmp(lhs, rhs) < 0; };
|
||||
|
||||
if (limit)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
#endif
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
else
|
||||
std::sort(res.begin(), res.end(), less);
|
||||
}
|
||||
@ -842,11 +835,7 @@ void ColumnArray::updatePermutationImpl(size_t limit, Permutation & res, EqualRa
|
||||
return;
|
||||
|
||||
/// Since then we are working inside the interval.
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
auto new_first = first;
|
||||
for (auto j = first + 1; j < limit; ++j)
|
||||
{
|
||||
|
@ -7,10 +7,8 @@
|
||||
#include <Core/BigInt.h>
|
||||
|
||||
#include <common/unaligned.h>
|
||||
#include <common/sort.h>
|
||||
#include <ext/scope_guard.h>
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
|
||||
#include <IO/WriteHelpers.h>
|
||||
@ -197,21 +195,11 @@ void ColumnDecimal<T>::updatePermutation(bool reverse, size_t limit, int, IColum
|
||||
/// Since then we are working inside the interval.
|
||||
|
||||
if (reverse)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last,
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last,
|
||||
[this](size_t a, size_t b) { return data[a] > data[b]; });
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last,
|
||||
[this](size_t a, size_t b) { return data[a] > data[b]; });
|
||||
#endif
|
||||
else
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last,
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last,
|
||||
[this](size_t a, size_t b) { return data[a] < data[b]; });
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last,
|
||||
[this](size_t a, size_t b) { return data[a] > data[b]; });
|
||||
#endif
|
||||
auto new_first = first;
|
||||
for (auto j = first + 1; j < limit; ++j)
|
||||
{
|
||||
|
@ -1,15 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Columns/ColumnVectorHelper.h>
|
||||
#include <Columns/IColumn.h>
|
||||
#include <Columns/IColumnImpl.h>
|
||||
#include <Columns/ColumnVectorHelper.h>
|
||||
#include <Core/Field.h>
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <common/sort.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -256,17 +254,9 @@ protected:
|
||||
sort_end = res.begin() + limit;
|
||||
|
||||
if (reverse)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), sort_end, res.end(), [this](size_t a, size_t b) { return data[a] > data[b]; });
|
||||
#else
|
||||
std::partial_sort(res.begin(), sort_end, res.end(), [this](size_t a, size_t b) { return data[a] > data[b]; });
|
||||
#endif
|
||||
partial_sort(res.begin(), sort_end, res.end(), [this](size_t a, size_t b) { return data[a] > data[b]; });
|
||||
else
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), sort_end, res.end(), [this](size_t a, size_t b) { return data[a] < data[b]; });
|
||||
#else
|
||||
std::partial_sort(res.begin(), sort_end, res.end(), [this](size_t a, size_t b) { return data[a] < data[b]; });
|
||||
#endif
|
||||
partial_sort(res.begin(), sort_end, res.end(), [this](size_t a, size_t b) { return data[a] < data[b]; });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
#include <Columns/ColumnFixedString.h>
|
||||
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/memcpySmall.h>
|
||||
#include <Common/memcmpSmall.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
|
||||
#include <ext/scope_guard.h>
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
#include <DataStreams/ColumnGathererStream.h>
|
||||
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/memcmpSmall.h>
|
||||
#include <Common/memcpySmall.h>
|
||||
#include <common/sort.h>
|
||||
#include <ext/scope_guard.h>
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#if defined(__SSE2__)
|
||||
# include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
@ -160,17 +155,9 @@ void ColumnFixedString::getPermutation(bool reverse, size_t limit, int /*nan_dir
|
||||
if (limit)
|
||||
{
|
||||
if (reverse)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), less<false>(*this));
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less<false>(*this));
|
||||
#endif
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), less<false>(*this));
|
||||
else
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), less<true>(*this));
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less<true>(*this));
|
||||
#endif
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), less<true>(*this));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -228,17 +215,9 @@ void ColumnFixedString::updatePermutation(bool reverse, size_t limit, int, Permu
|
||||
/// Since then we are working inside the interval.
|
||||
|
||||
if (reverse)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less<false>(*this));
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less<false>(*this));
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less<false>(*this));
|
||||
else
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less<true>(*this));
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less<true>(*this));
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less<true>(*this));
|
||||
|
||||
auto new_first = first;
|
||||
for (auto j = first + 1; j < limit; ++j)
|
||||
|
@ -1,20 +1,19 @@
|
||||
#include <Columns/ColumnLowCardinality.h>
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
#include <DataStreams/ColumnGathererStream.h>
|
||||
#include <DataTypes/NumberTraits.h>
|
||||
#include <Common/HashTable/HashMap.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/WeakHash.h>
|
||||
|
||||
#include <Common/assert_cast.h>
|
||||
#include <common/sort.h>
|
||||
#include <ext/scope_guard.h>
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
@ -397,11 +396,7 @@ void ColumnLowCardinality::updatePermutationImpl(size_t limit, Permutation & res
|
||||
|
||||
/// Since then we are working inside the interval.
|
||||
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
auto new_first = first;
|
||||
|
||||
for (auto j = first + 1; j < limit; ++j)
|
||||
|
@ -1,18 +1,16 @@
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/memcmpSmall.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Columns/Collator.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
|
||||
#include <Columns/Collator.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
#include <DataStreams/ColumnGathererStream.h>
|
||||
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/memcmpSmall.h>
|
||||
#include <common/sort.h>
|
||||
#include <common/unaligned.h>
|
||||
#include <ext/scope_guard.h>
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -317,11 +315,7 @@ void ColumnString::getPermutationImpl(size_t limit, Permutation & res, Comparato
|
||||
auto less = [&cmp](size_t lhs, size_t rhs){ return cmp(lhs, rhs) < 0; };
|
||||
|
||||
if (limit)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
#endif
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
else
|
||||
std::sort(res.begin(), res.end(), less);
|
||||
}
|
||||
@ -372,11 +366,7 @@ void ColumnString::updatePermutationImpl(size_t limit, Permutation & res, EqualR
|
||||
return;
|
||||
|
||||
/// Since then we are working inside the interval.
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less);
|
||||
|
||||
size_t new_first = first;
|
||||
for (size_t j = first + 1; j < limit; ++j)
|
||||
|
@ -1,17 +1,16 @@
|
||||
#include <Columns/ColumnTuple.h>
|
||||
|
||||
#include <Columns/IColumnImpl.h>
|
||||
#include <Core/Field.h>
|
||||
#include <DataStreams/ColumnGathererStream.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/Operators.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <common/sort.h>
|
||||
#include <ext/map.h>
|
||||
#include <ext/range.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Core/Field.h>
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -354,17 +353,9 @@ void ColumnTuple::getPermutationImpl(size_t limit, Permutation & res, LessOperat
|
||||
limit = 0;
|
||||
|
||||
if (limit)
|
||||
{
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
#endif
|
||||
}
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), less);
|
||||
else
|
||||
{
|
||||
std::sort(res.begin(), res.end(), less);
|
||||
}
|
||||
}
|
||||
|
||||
void ColumnTuple::updatePermutationImpl(bool reverse, size_t limit, int nan_direction_hint, IColumn::Permutation & res, EqualRanges & equal_ranges, const Collator * collator) const
|
||||
|
@ -1,28 +1,27 @@
|
||||
#include "ColumnVector.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <common/unaligned.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/NaNUtils.h>
|
||||
#include <Common/RadixSort.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <pdqsort.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
#include <DataStreams/ColumnGathererStream.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Common/NaNUtils.h>
|
||||
#include <Common/RadixSort.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/WeakHash.h>
|
||||
#include <Common/assert_cast.h>
|
||||
#include <common/sort.h>
|
||||
#include <common/unaligned.h>
|
||||
#include <ext/bit_cast.h>
|
||||
#include <ext/scope_guard.h>
|
||||
#include <pdqsort.h>
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
#include <miniselect/floyd_rivest_select.h> // Y_IGNORE
|
||||
#endif
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__SSE2__)
|
||||
# include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace DB
|
||||
@ -158,17 +157,9 @@ void ColumnVector<T>::getPermutation(bool reverse, size_t limit, int nan_directi
|
||||
res[i] = i;
|
||||
|
||||
if (reverse)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), greater(*this, nan_direction_hint));
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), greater(*this, nan_direction_hint));
|
||||
#endif
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), greater(*this, nan_direction_hint));
|
||||
else
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin(), res.begin() + limit, res.end(), less(*this, nan_direction_hint));
|
||||
#else
|
||||
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less(*this, nan_direction_hint));
|
||||
#endif
|
||||
partial_sort(res.begin(), res.begin() + limit, res.end(), less(*this, nan_direction_hint));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -264,17 +255,9 @@ void ColumnVector<T>::updatePermutation(bool reverse, size_t limit, int nan_dire
|
||||
/// Since then, we are working inside the interval.
|
||||
|
||||
if (reverse)
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, greater(*this, nan_direction_hint));
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, greater(*this, nan_direction_hint));
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, greater(*this, nan_direction_hint));
|
||||
else
|
||||
#if !defined(ARCADIA_BUILD)
|
||||
miniselect::floyd_rivest_partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less(*this, nan_direction_hint));
|
||||
#else
|
||||
std::partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less(*this, nan_direction_hint));
|
||||
#endif
|
||||
partial_sort(res.begin() + first, res.begin() + limit, res.begin() + last, less(*this, nan_direction_hint));
|
||||
|
||||
size_t new_first = first;
|
||||
for (size_t j = first + 1; j < limit; ++j)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Columns/IColumn.h>
|
||||
#include <Common/PODArray.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -1215,6 +1215,20 @@ void MergeTreeData::clearOldWriteAheadLogs()
|
||||
}
|
||||
}
|
||||
|
||||
void MergeTreeData::clearEmptyParts()
|
||||
{
|
||||
auto parts = getDataPartsVector();
|
||||
for (const auto & part : parts)
|
||||
{
|
||||
if (part->rows_count == 0)
|
||||
{
|
||||
ASTPtr literal = std::make_shared<ASTLiteral>(part->name);
|
||||
/// If another replica has already started drop, it's ok, no need to throw.
|
||||
dropPartition(literal, /* detach = */ false, /*drop_part = */ true, global_context, /* throw_if_noop = */ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MergeTreeData::rename(const String & new_table_path, const StorageID & new_table_id)
|
||||
{
|
||||
auto disks = getStoragePolicy()->getDisks();
|
||||
|
@ -498,6 +498,8 @@ public:
|
||||
/// Must be called with locked lockForShare() because use relative_data_path.
|
||||
void clearOldTemporaryDirectories(ssize_t custom_directories_lifetime_seconds = -1);
|
||||
|
||||
void clearEmptyParts();
|
||||
|
||||
/// After the call to dropAllData() no method can be called.
|
||||
/// Deletes the data directory and flushes the uncompressed blocks cache and the marks cache.
|
||||
void dropAllData();
|
||||
@ -876,7 +878,7 @@ protected:
|
||||
// Partition helpers
|
||||
bool canReplacePartition(const DataPartPtr & src_part) const;
|
||||
|
||||
virtual void dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & context) = 0;
|
||||
virtual void dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & context, bool throw_if_noop = true) = 0;
|
||||
virtual PartitionCommandsResultInfo attachPartition(const ASTPtr & partition, const StorageMetadataPtr & metadata_snapshot, bool part, const Context & context) = 0;
|
||||
virtual void replacePartitionFrom(const StoragePtr & source_table, const ASTPtr & partition, bool replace, const Context & context) = 0;
|
||||
virtual void movePartitionToTable(const StoragePtr & dest_table, const ASTPtr & partition, const Context & context) = 0;
|
||||
|
@ -72,6 +72,7 @@ void ReplicatedMergeTreeCleanupThread::iterate()
|
||||
clearOldLogs();
|
||||
clearOldBlocks();
|
||||
clearOldMutations();
|
||||
storage.clearEmptyParts();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,8 @@ void ReplicatedMergeTreeQueue::addVirtualParts(const MergeTreeData::DataParts &
|
||||
bool ReplicatedMergeTreeQueue::isVirtualPart(const MergeTreeData::DataPartPtr & data_part) const
|
||||
{
|
||||
std::lock_guard lock(state_mutex);
|
||||
return virtual_parts.getContainingPart(data_part->info) != data_part->name;
|
||||
auto virtual_part_name = virtual_parts.getContainingPart(data_part->info);
|
||||
return !virtual_part_name.empty() && virtual_part_name != data_part->name;
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,6 +99,7 @@ void StorageMergeTree::startup()
|
||||
{
|
||||
clearOldPartsFromFilesystem();
|
||||
clearOldWriteAheadLogs();
|
||||
clearEmptyParts();
|
||||
|
||||
/// Temporary directories contain incomplete results of merges (after forced restart)
|
||||
/// and don't allow to reinitialize them, so delete each of them immediately
|
||||
@ -947,6 +948,7 @@ std::optional<JobAndPool> StorageMergeTree::getDataProcessingJob()
|
||||
clearOldTemporaryDirectories();
|
||||
clearOldWriteAheadLogs();
|
||||
clearOldMutations();
|
||||
clearEmptyParts();
|
||||
}, PoolType::MERGE_MUTATE};
|
||||
}
|
||||
return {};
|
||||
@ -1087,7 +1089,7 @@ ActionLock StorageMergeTree::stopMergesAndWait()
|
||||
}
|
||||
|
||||
|
||||
void StorageMergeTree::dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & context)
|
||||
void StorageMergeTree::dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & context, bool throw_if_noop)
|
||||
{
|
||||
{
|
||||
/// Asks to complete merges and does not allow them to start.
|
||||
@ -1105,8 +1107,10 @@ void StorageMergeTree::dropPartition(const ASTPtr & partition, bool detach, bool
|
||||
|
||||
if (part)
|
||||
parts_to_remove.push_back(part);
|
||||
else
|
||||
else if (throw_if_noop)
|
||||
throw Exception("Part " + part_name + " not found, won't try to drop it.", ErrorCodes::NO_SUCH_DATA_PART);
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -187,7 +187,7 @@ private:
|
||||
void clearOldMutations(bool truncate = false);
|
||||
|
||||
// Partition helpers
|
||||
void dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & context) override;
|
||||
void dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & context, bool throw_if_noop) override;
|
||||
PartitionCommandsResultInfo attachPartition(const ASTPtr & partition, const StorageMetadataPtr & metadata_snapshot, bool part, const Context & context) override;
|
||||
|
||||
void replacePartitionFrom(const StoragePtr & source_table, const ASTPtr & partition, bool replace, const Context & context) override;
|
||||
|
@ -4262,7 +4262,7 @@ bool StorageReplicatedMergeTree::getFakePartCoveringAllPartsInPartition(const St
|
||||
}
|
||||
|
||||
|
||||
void StorageReplicatedMergeTree::dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & query_context)
|
||||
void StorageReplicatedMergeTree::dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & query_context, bool throw_if_noop)
|
||||
{
|
||||
assertNotReadonly();
|
||||
if (!is_leader)
|
||||
@ -4276,7 +4276,7 @@ void StorageReplicatedMergeTree::dropPartition(const ASTPtr & partition, bool de
|
||||
if (drop_part)
|
||||
{
|
||||
String part_name = partition->as<ASTLiteral &>().value.safeGet<String>();
|
||||
did_drop = dropPart(zookeeper, part_name, entry, detach);
|
||||
did_drop = dropPart(zookeeper, part_name, entry, detach, throw_if_noop);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -5969,7 +5969,7 @@ bool StorageReplicatedMergeTree::waitForShrinkingQueueSize(size_t queue_size, UI
|
||||
}
|
||||
|
||||
bool StorageReplicatedMergeTree::dropPart(
|
||||
zkutil::ZooKeeperPtr & zookeeper, String part_name, LogEntry & entry, bool detach)
|
||||
zkutil::ZooKeeperPtr & zookeeper, String part_name, LogEntry & entry, bool detach, bool throw_if_noop)
|
||||
{
|
||||
LOG_TRACE(log, "Will try to insert a log entry to DROP_RANGE for part: " + part_name);
|
||||
|
||||
@ -5982,32 +5982,52 @@ bool StorageReplicatedMergeTree::dropPart(
|
||||
auto part = getPartIfExists(part_info, {MergeTreeDataPartState::Committed});
|
||||
|
||||
if (!part)
|
||||
throw Exception("Part " + part_name + " not found locally, won't try to drop it.", ErrorCodes::NO_SUCH_DATA_PART);
|
||||
{
|
||||
if (throw_if_noop)
|
||||
throw Exception("Part " + part_name + " not found locally, won't try to drop it.", ErrorCodes::NO_SUCH_DATA_PART);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// There isn't a lot we can do otherwise. Can't cancel merges because it is possible that a replica already
|
||||
/// finished the merge.
|
||||
if (partIsAssignedToBackgroundOperation(part))
|
||||
throw Exception("Part " + part_name
|
||||
+ " is currently participating in a background operation (mutation/merge)"
|
||||
+ ", try again later", ErrorCodes::PART_IS_TEMPORARILY_LOCKED);
|
||||
{
|
||||
if (throw_if_noop)
|
||||
throw Exception("Part " + part_name
|
||||
+ " is currently participating in a background operation (mutation/merge)"
|
||||
+ ", try again later", ErrorCodes::PART_IS_TEMPORARILY_LOCKED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (partIsLastQuorumPart(part->info))
|
||||
throw Exception("Part " + part_name + " is last inserted part with quorum in partition. Cannot drop",
|
||||
ErrorCodes::NOT_IMPLEMENTED);
|
||||
{
|
||||
if (throw_if_noop)
|
||||
throw Exception("Part " + part_name + " is last inserted part with quorum in partition. Cannot drop",
|
||||
ErrorCodes::NOT_IMPLEMENTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (partIsInsertingWithParallelQuorum(part->info))
|
||||
throw Exception("Part " + part_name + " is inserting with parallel quorum. Cannot drop",
|
||||
ErrorCodes::NOT_IMPLEMENTED);
|
||||
{
|
||||
if (throw_if_noop)
|
||||
throw Exception("Part " + part_name + " is inserting with parallel quorum. Cannot drop",
|
||||
ErrorCodes::NOT_IMPLEMENTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
Coordination::Requests ops;
|
||||
getClearBlocksInPartitionOps(ops, *zookeeper, part_info.partition_id, part_info.min_block, part_info.max_block);
|
||||
size_t clean_block_ops_size = ops.size();
|
||||
|
||||
/// Set fake level to treat this part as virtual in queue.
|
||||
auto drop_part_info = part->info;
|
||||
drop_part_info.level = MergeTreePartInfo::MAX_LEVEL;
|
||||
|
||||
/// If `part_name` is result of a recent merge and source parts are still available then
|
||||
/// DROP_RANGE with detach will move this part together with source parts to `detached/` dir.
|
||||
entry.type = LogEntry::DROP_RANGE;
|
||||
entry.source_replica = replica_name;
|
||||
entry.new_part_name = part_name;
|
||||
entry.new_part_name = drop_part_info.getPartName();
|
||||
entry.detach = detach;
|
||||
entry.create_time = time(nullptr);
|
||||
|
||||
|
@ -555,12 +555,12 @@ private:
|
||||
/// Info about how other replicas can access this one.
|
||||
ReplicatedMergeTreeAddress getReplicatedMergeTreeAddress() const;
|
||||
|
||||
bool dropPart(zkutil::ZooKeeperPtr & zookeeper, String part_name, LogEntry & entry, bool detach);
|
||||
bool dropPart(zkutil::ZooKeeperPtr & zookeeper, String part_name, LogEntry & entry, bool detach, bool throw_if_noop);
|
||||
bool dropAllPartsInPartition(
|
||||
zkutil::ZooKeeper & zookeeper, String & partition_id, LogEntry & entry, bool detach);
|
||||
|
||||
// Partition helpers
|
||||
void dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & query_context) override;
|
||||
void dropPartition(const ASTPtr & partition, bool detach, bool drop_part, const Context & query_context, bool throw_if_noop) override;
|
||||
PartitionCommandsResultInfo attachPartition(const ASTPtr & partition, const StorageMetadataPtr & metadata_snapshot, bool part, const Context & query_context) override;
|
||||
void replacePartitionFrom(const StoragePtr & source_table, const ASTPtr & partition, bool replace, const Context & query_context) override;
|
||||
void movePartitionToTable(const StoragePtr & dest_table, const ASTPtr & partition, const Context & query_context) override;
|
||||
|
@ -213,6 +213,14 @@ def test_ttl_double_delete_rule_returns_error(started_cluster):
|
||||
assert False
|
||||
|
||||
|
||||
def optimize_with_retry(node, table_name, retry=20):
|
||||
for i in range(retry):
|
||||
try:
|
||||
node.query("OPTIMIZE TABLE {name} FINAL SETTINGS optimize_throw_if_noop = 1".format(name=table_name), settings={"optimize_throw_if_noop": "1"})
|
||||
break
|
||||
except e:
|
||||
time.sleep(0.5)
|
||||
|
||||
@pytest.mark.parametrize("name,engine", [
|
||||
("test_ttl_alter_delete", "MergeTree()"),
|
||||
("test_replicated_ttl_alter_delete", "ReplicatedMergeTree('/clickhouse/test_replicated_ttl_alter_delete', '1')"),
|
||||
@ -238,14 +246,6 @@ limitations under the License."""
|
||||
"""
|
||||
drop_table([node1], name)
|
||||
|
||||
def optimize_with_retry(retry=20):
|
||||
for i in range(retry):
|
||||
try:
|
||||
node1.query("OPTIMIZE TABLE {name} FINAL".format(name=name), settings={"optimize_throw_if_noop": "1"})
|
||||
break
|
||||
except:
|
||||
time.sleep(0.5)
|
||||
|
||||
node1.query(
|
||||
"""
|
||||
CREATE TABLE {name} (
|
||||
@ -267,7 +267,7 @@ limitations under the License."""
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
optimize_with_retry()
|
||||
optimize_with_retry(node1, name)
|
||||
r = node1.query("SELECT s1, b1 FROM {name} ORDER BY b1, s1".format(name=name)).splitlines()
|
||||
assert r == ["\t1", "hello2\t2"]
|
||||
|
||||
@ -277,7 +277,55 @@ limitations under the License."""
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
optimize_with_retry()
|
||||
optimize_with_retry(node1, name)
|
||||
|
||||
r = node1.query("SELECT s1, b1 FROM {name} ORDER BY b1, s1".format(name=name)).splitlines()
|
||||
assert r == ["\t0", "\t0", "hello2\t2"]
|
||||
|
||||
def test_ttl_empty_parts(started_cluster):
|
||||
drop_table([node1, node2], "test_ttl_empty_parts")
|
||||
for node in [node1, node2]:
|
||||
node.query(
|
||||
'''
|
||||
CREATE TABLE test_ttl_empty_parts(date Date, id UInt32)
|
||||
ENGINE = ReplicatedMergeTree('/clickhouse/tables/test/test_ttl', '{replica}')
|
||||
ORDER BY id
|
||||
SETTINGS max_bytes_to_merge_at_min_space_in_pool = 1, max_bytes_to_merge_at_max_space_in_pool = 1,
|
||||
cleanup_delay_period = 1, cleanup_delay_period_random_add = 0
|
||||
'''.format(replica=node.name))
|
||||
|
||||
for i in range (1, 7):
|
||||
node1.query("INSERT INTO test_ttl_empty_parts SELECT '2{}00-01-0{}', number FROM numbers(1000)".format(i % 2, i))
|
||||
|
||||
assert node1.query("SELECT count() FROM test_ttl_empty_parts") == "6000\n"
|
||||
assert node1.query("SELECT name FROM system.parts WHERE table = 'test_ttl_empty_parts' AND active ORDER BY name") == \
|
||||
"all_0_0_0\nall_1_1_0\nall_2_2_0\nall_3_3_0\nall_4_4_0\nall_5_5_0\n"
|
||||
|
||||
node1.query("ALTER TABLE test_ttl_empty_parts MODIFY TTL date")
|
||||
|
||||
assert node1.query("SELECT count() FROM test_ttl_empty_parts") == "3000\n"
|
||||
|
||||
time.sleep(3) # Wait for cleanup thread
|
||||
assert node1.query("SELECT name FROM system.parts WHERE table = 'test_ttl_empty_parts' AND active ORDER BY name") == \
|
||||
"all_0_0_0_6\nall_2_2_0_6\nall_4_4_0_6\n"
|
||||
|
||||
for node in [node1, node2]:
|
||||
node.query("ALTER TABLE test_ttl_empty_parts MODIFY SETTING max_bytes_to_merge_at_min_space_in_pool = 1000000000")
|
||||
node.query("ALTER TABLE test_ttl_empty_parts MODIFY SETTING max_bytes_to_merge_at_max_space_in_pool = 1000000000")
|
||||
|
||||
optimize_with_retry(node1, 'test_ttl_empty_parts')
|
||||
assert node1.query("SELECT name FROM system.parts WHERE table = 'test_ttl_empty_parts' AND active ORDER BY name") == "all_0_4_1_6\n"
|
||||
|
||||
# Check that after removing empty parts mutations and merges works
|
||||
node1.query("INSERT INTO test_ttl_empty_parts SELECT '2100-01-20', number FROM numbers(1000)")
|
||||
node1.query("ALTER TABLE test_ttl_empty_parts DELETE WHERE id % 2 = 0 SETTINGS mutations_sync = 2")
|
||||
assert node1.query("SELECT count() FROM test_ttl_empty_parts") == "2000\n"
|
||||
|
||||
optimize_with_retry(node1, 'test_ttl_empty_parts')
|
||||
assert node1.query("SELECT name FROM system.parts WHERE table = 'test_ttl_empty_parts' AND active ORDER BY name") == "all_0_7_2_8\n"
|
||||
|
||||
node2.query('SYSTEM SYNC REPLICA test_ttl_empty_parts', timeout=20)
|
||||
|
||||
error_msg = '<Error> default.test_ttl_empty_parts (ReplicatedMergeTreeCleanupThread)'
|
||||
assert not node1.contains_in_log(error_msg)
|
||||
assert not node2.contains_in_log(error_msg)
|
||||
|
@ -0,0 +1,4 @@
|
||||
1000
|
||||
2
|
||||
500
|
||||
1
|
20
tests/queries/0_stateless/01560_ttl_remove_empty_parts.sql
Normal file
20
tests/queries/0_stateless/01560_ttl_remove_empty_parts.sql
Normal file
@ -0,0 +1,20 @@
|
||||
DROP TABLE IF EXISTS ttl_empty_parts;
|
||||
|
||||
CREATE TABLE ttl_empty_parts (id UInt32, d Date) ENGINE = MergeTree ORDER BY tuple() PARTITION BY id;
|
||||
|
||||
INSERT INTO ttl_empty_parts SELECT 0, toDate('2005-01-01') + number from numbers(500);
|
||||
INSERT INTO ttl_empty_parts SELECT 1, toDate('2050-01-01') + number from numbers(500);
|
||||
|
||||
SELECT count() FROM ttl_empty_parts;
|
||||
SELECT count() FROM system.parts WHERE table = 'ttl_empty_parts' AND database = currentDatabase() AND active;
|
||||
|
||||
ALTER TABLE ttl_empty_parts MODIFY TTL d;
|
||||
|
||||
-- To be sure, that task, which clears outdated parts executed.
|
||||
DETACH TABLE ttl_empty_parts;
|
||||
ATTACH TABLE ttl_empty_parts;
|
||||
|
||||
SELECT count() FROM ttl_empty_parts;
|
||||
SELECT count() FROM system.parts WHERE table = 'ttl_empty_parts' AND database = currentDatabase() AND active;
|
||||
|
||||
DROP TABLE ttl_empty_parts;
|
@ -168,3 +168,4 @@
|
||||
01555_system_distribution_queue_mask
|
||||
01557_max_parallel_replicas_no_sample.sql
|
||||
01525_select_with_offset_fetch_clause
|
||||
01560_timeseriesgroupsum_segfault
|
||||
|
@ -1,34 +1,35 @@
|
||||
**Анализ запроса в Clickhouse**
|
||||
# Clickhouse query analysis
|
||||
|
||||
В данной работе мы будем рассматривать только select запросы, то есть те запросы, которые из таблицы достают данные.
|
||||
Встроенный парсер Clickhouse принимает на вход строку, которая является запросом. В select запросе выделяется 14 основных частей: WITH, SELECT, TABLES, PREWHERE, WHERE, GROUP_BY, HAVING, ORDER_BY, LIMIT_BY_OFFSET, LIMIT_BY_LENGTH, LIMIT_BY, LIMIT_OFFSET, LIMIT_LENGTH, SETTINGS. Мы будем рассматривать части SELECT, TABLES, WHERE, GROUP_BY, HAVING, ORDER_BY так как именно в них находятся основные данные, нужные нам для анализа структуры и выявления значений. После анализа запроса парсер выдает нам древовидную структуру, где каждая вершина является определенной операцией выполнения запроса, функцией над значениями, константой, обозначением и тому подобное. Вершины также имеют свои поддеревья, в которых находятся их аргументы или подоперации. Обходя данное дерево мы будем пытаться выявить необходимые нам данные.
|
||||
Here we will consider only `SELECT` queries, i.e. those queries that get data from the table.
|
||||
The built-in Clickhouse parser accepts a string as input, which is a query. Among 14 main clauses of `SELECT` statement: `WITH`, `SELECT`, `TABLES`, `PREWHERE`, `WHERE`, `GROUP_BY`, `HAVING`, `ORDER_BY`, `LIMIT_BY_OFFSET`, `LIMIT_BY_LENGTH`, `LIMIT_BY`, `LIMIT_OFFSET`, `LIMIT_LENGTH`, `SETTINGS`, we will analyze the `SELECT`, `TABLES`, `WHERE`, `GROUP_BY`, `HAVING`, `ORDER_BY` clauses because the most of data is there. We need this data to analyze the structure and to identify values. The parser issues a tree structure after parsing a query, where each node is a specific query execution operation, a function over values, a constant, a designation, etc. Nodes also have subtrees where their arguments or suboperations are located. We will try to reveal the data we need by avoiding this tree.
|
||||
|
||||
**Анализ схемы**
|
||||
## Scheme analysis
|
||||
|
||||
По запросу необходимо определить возможные таблицы. Имея строку запроса можно понять, какие его части обозначают названия таблиц, таким образом можно определить их количество в нашей базе данных.
|
||||
В парсере Clickhouse поддеревом запроса, отвечающее за таблицы из которых мы берем данные, является TABLES (Рисунок 1), в нем лежит основная таблица, из которой берутся колонки, а также операции JOIN, которые совершаются в запросе. Обходя все вершины в поддереве мы берем названия таблиц и баз данных в которых они лежат, а также их алиас, то есть укороченные названия, выбранные автором запроса. Эти названия могут понадобиться нам для определения принадлежности колонки в дальнейшем.
|
||||
Таким образом для запроса мы получаем набор баз данных, а также таблиц и их условных обозначений (алиасов), по которым делается запрос.
|
||||
It is necessary to determine possible tables by a query. Having a query string, you can understand which parts of it represent the names of the tables, so you can determine their number in our database.
|
||||
In the Clickhouse parser, `TABLES` (Figure 1) is a query subtree responsible for tables where we get data. It contains the main table where the columns come from, as well as the `JOIN` operations that are performed in the query. Avoiding all nodes in the subtree, we use the names of the tables and databases where they are located, as well as their alias, i.e. the shortened names chosen by the query author. We may need these names to determine the ownership of the column in the future.
|
||||
Thus, we get a set of databases for the query, as well as tables and their aliases, with the help of them a query is made.
|
||||
|
||||
Затем нам необходимо определить множество столбцов, которые присутствуют в запросе и таблицы, к которым они могут относиться. Во время исполнения запроса уже известно множество столбцов в каждой таблице, поэтому при исполнении программа автоматически связывает столбец и таблицу, однако в нашем случае нельзя однозначно трактовать принадлежность столбца к определенной таблице, например в следующем запросе: “SELECT column1, column2, column3 FROM table1 JOIN table2 on table1.column2 = table2.column3 ”. Здесь мы однозначно можем сказать, к какой таблице относятся колонки column2 и column3, однако column1 может принадлежать как первой, так и второй таблице. Для однозначности трактовки таких случаев, мы будем относить данную неопределенные колонки к основной таблице, по которой делается запрос, например в данном случае это будет таблица table1.
|
||||
Все столбцы в дереве лежат в вершинах типа IDENTIFIER, которые находятся в поддеревьях SELECT, TABLES, WHERE, GROUP_BY, HAVING, ORDER_BY. Рекурсивно обходя поддеревья мы формируем множество всех таблиц, затем мы разделяем колонку на составляющие: таблица (если она явно указана через точку) и само название, затем, так как таблица может являться алиасом, мы заменяем алиас на оригинальное название таблицы. Теперь у нас есть список всех столбцов и таблиц, к которым они относятся, для столбцов без таблиц определяем основную таблицу запроса.
|
||||
Then we need to define the set of columns that are in the query and the tables they can refer to. The set of columns in each table is already known during the query execution. Therefore, the program automatically links the column and table at runtime. However, in our case, it is impossible to unambiguously interpret the belonging of a column to a specific table, for example, in the following query `SELECT column1, column2, column3 FROM table1 JOIN table2 on table1.column2 = table2.column3`. In this case, we can say which table `column2` and `column3` belong to. However, `column1` can belong to either the first or the second table. We will refer undefined columns to the main table, on which a query is made, for unambiguous interpretation of such cases. For example, in this case, it will be `table1`.
|
||||
All columns in the tree are in `IDENTIFIER` type nodes, which are in the `SELECT`, `TABLES`, `WHERE`, `GROUP_BY`, `HAVING`, `ORDER_BY` subtrees. We form a set of all tables recursively avoiding the subtrees, then we split the column into constituents such as the table (if it is explicitly specified with a dot) and the name. Then, since the table can be an alias, we replace the alias with the original table name. We now have a list of all the columns and tables they belong to. We define the main query table for non-table columns.
|
||||
|
||||
**Анализ столбцов**
|
||||
## Column analysis
|
||||
|
||||
Продолжением является точное определение типов данных для столбцов, у которых в запросе присутствует значение. Примером являются логические условие WHERE, в котором у определенного набора атрибутов проверяется логическое выражение. Если в запросе указано column > 5, то можно сделать вывод, что в данном столбце содержится численное значение, либо если на атрибут применяется выражение LIKE, то атрибут представляет собой строковый тип.
|
||||
В данной части необходимо научится вычленять из запроса все таки выражения и сопоставлять типы данных для тех столбцов, для которых это возможно сделать. При этом, понятно, что из присутствующих значений не всегда можно сделать однозначное решение о типе конкретного атрибута, например column > 5 может означать множество численных типов таких как UINT8, UINT32, INT32, INT64 и тому подобных. Здесь нужно определиться с трактовкой определенных значений, так как перебор всех возможных может быть достаточно большим, а поэтому занимать продолжительное время.
|
||||
Для числовых значений было решено использовать INT64(целочисленный тип 64 битности) для целочисленных значений и FLOAT64(число с плавающей точкой 64 битности) для нецелых значений. Также используются типы STRING для строковых значений, DATE для дат, DATETIME для времени. Стоит заметить, что существует еще тип ARRAY, который является оберткой над предыдущими типами и представлять собой массив из значений определенного типа.
|
||||
Определить значения столбцов мы можем используя логический, арифметические и другие функции над значениями столбцов, которые указаны в запросе. Такие функции лежат в поддеревьях SELECT и WHERE. Параметром функции может быть константа, колонка либо другая функция (Рисунок 2). Таким образом для понимания типа колонки могут помочь следующие параметры: 1) Типы аргументов, которые может принимать функция, например функция TOSTARTOFMINUTE(округляет время до кратного 5 минутам вниз) может принимать только DATETIME, таким образом если аргументом данной функции является колонка, то данная колонка имеет тип DATETIME. 2) типы остальных аргументов в данной функции, например функция EQUALS(равенство), она подразумевает собой равенство типов ее аргументов, таким образом если в данной функции присутствует константа и столбец, то мы можем определить тип столбца как тип константы.
|
||||
Then we need to exactly define data types for columns that have a value in the query. An example is the boolean `WHERE` clause where we test boolean expressions in its attributes. If the query specifies `column > 5`, then we can conclude that this column contains a numeric value, or if the `LIKE` expression is applied to the attribute, then the attribute has a string type.
|
||||
In this part, you need to learn how to extract such expressions from a query and match data types for columns, where it is possible. At the same time, it is clear that it is not always possible to make an unambiguous decision about the type of a particular attribute from the available values. For example, `column > 5` can mean many numeric types such as `UINT8`, `UINT32`, `INT32`, `INT64`, etc. It is necessary to determine the interpretation of certain values since searching through all possible values can be quite large and long.
|
||||
It can take a long time to iterate over all possible values, so we use `INT64` and `FLOAT64` types for numeric values, `STRING` for strings, `DATE` and `DATETIME` for dates, and `ARRAY`.
|
||||
We can determine column values using boolean, arithmetic and other functions on the column values that are specified in the query. Such functions are in the `SELECT` and `WHERE` subtrees. The function parameter can be a constant, a column or another function (Figure 2). Thus, the following parameters can help to understand the type of the column:
|
||||
- The types of arguments that a function can take, for example, the `TOSTARTOFMINUTE` function (truncate time up to a multiple of 5 minutes down) can only accept `DATETIME`, so if the argument of this function is a column, then this column has `DATETIME` type.
|
||||
- The types of the remaining arguments in this function. For example, the `EQUALS` function means equality of its argument types, so if a constant and a column are present in this function, then we can define the type of the column as the type of the constant.
|
||||
|
||||
Таким образом, для каждой функции мы определяем возможные типы аргументов, тип возвращаемого значения, а также параметр, являются ли аргументы функции одинакового типа. Рекурсивный обработчик функций будет определять возможные типы столбцов использующихся в данных функциях по значениям аргументов и возвращать возможные типы результата выполнения функции.
|
||||
Теперь для каждого столбца мы имеем множество возможных типов его значений. Для однозначной трактовки запроса мы выберем один конкретный тип из этого множества.
|
||||
Thus, we define the possible argument types, the return type, the parameter for each function, and the function arguments of the identical type. The recursive function handler will determine the possible types of columns used in these functions by the values of the arguments, and then return the possible types of the function's result.
|
||||
Now, for each column, we have many possible types of values. We will choose one specific type from this set to interpret the query unambiguously.
|
||||
|
||||
**Определение значений столбцов**
|
||||
## Column values definition
|
||||
|
||||
На этом этапе мы уже имеем определенную структуру таблиц базы данных, нам необходимо заполнить эту таблицу значениям. Нам необходимо понять, какие столбцы зависят друг от друга при исполнении функции (например по двум столбцами делается join, значит они должны иметь одинаковые значения), а также какие значения должны принимать столбцы, чтобы выполнялись различные условия при исполнении.
|
||||
Для достижения цели ищем все операции сравнения в нашем запросе, если аргументами операции являются два столбца, то мы считаем их связанными, если аргументами являются столбец и значение, то присваиваем данное значение возможным значением данного столбца, а также добавляем данное значение + определенный шум. Для числового типа шумом является случайное число, для даты - случайное количество дней и т.п. При этом для каждой операции сравнения необходим свой обработчик этой операции, который генерирует хотя бы два значения, одно из которых условие операции, а другое нет. Например, для операции column1 > 5, column1 должно присваиваться значение большее 5 и меньшее, либо равное 5, аналогично для операции “column2 LIKE some%string”, столбцу column2 должно присваиваться значение удовлетворяющее выражение, а также не удовлетворяющее.
|
||||
Теперь для некоторых колонок мы имеем множество связанных с ними колонок и множество значений. Мы знаем, что связность колонок симметрична, но для полноценного определения связности колонок нам необходимо добавить транзитивность, т.к если “column1 = column2” и “column2 = column3”, то “column1 = column3”, но это не вытекает из построения. Соответственно нам необходимо распространить связность по всем колонкам. Затем мы для каждой колонки объединяем множество ее значений со значениями всех связанных с ней. Теперь если у нас остались колонки без значений, мы просто генерируем случайные значения.
|
||||
At this stage, we already have a certain structure of the database tables, we need to fill this table with values. We should understand which columns depend on each other when executing the function (for example, the join is done according to two columns, which means that they must have the same values). We also need to understand what values the columns must have to fulfill various conditions during execution.
|
||||
We search for all comparison operations in our query to achieve the goal. If the arguments of the operation are two columns, then we consider them linked. If the arguments are the column and the value, then we assign that value to the possible column value and add the value with some noise. A random number is a noise for a numeric type, it is a random number of days for a date, etc. In this case, a handler for this operation is required for each comparison operation, which generates at least two values, one of them is the operation condition, and the other is not. For example, a value greater than 5 and less than or equal to 5 must be assigned for the operation `column1 > 5`, `column1`, for the operation `column2 LIKE some% string` the same is true. The satisfying and not satisfying expression must be assigned to `column2`.
|
||||
Now we have many associated columns and many values. We know that the connectivity of columns is symmetric, but we need to add transitivity for a complete definition, because if `column1 = column2` and `column2 = column3`, then `column1 = column3`, but this does not follow from the construction. Accordingly, we need to extend the connectivity across all columns. We combine multiple values for each column with the values associated with it. If we have columns with no values, then we generate random values.
|
||||
|
||||
**Генерация записей**
|
||||
## Generation
|
||||
|
||||
Теперь у нас есть полноценной представление схемы базы данных, а также множество значений каждой таблицы. Мы будем генерировать данные посредством декартова произведения множества значений каждого столбца для определенной таблицы. Таким образом мы получаем для каждой таблицы множество, состоящее из множеств значений каждого столбца.
|
||||
По этим данным мы начинаем генерировать запросы, создающие данную таблицу и заполняет ее данными. По структуре таблицы и типам ее столбцов мы генерируем CREATE QUERY, которая создает данную таблицу. Затем по множеству значений мы генерируем INSERT QUERY, которая заполняет данную таблицу данными.
|
||||
We have a complete view of the database schema as well as many values for each table now. We will generate data by cartesian product of the value set of each column for a specific table. Thus, we get a set for each table, consisting of sets of values for each column. We start generating queries that create this table and fill it with data. We generate the `CREATE QUERY` that creates this table based on the structure of the table and the types of its columns, and then we generate the `INSERT QUERY` over the set of values, which fills the table with data.
|
||||
|
@ -1,6 +1,9 @@
|
||||
v20.11.3.3-stable 2020-11-13
|
||||
v20.11.2.1-stable 2020-11-11
|
||||
v20.10.4.1-stable 2020-11-13
|
||||
v20.10.3.30-stable 2020-10-29
|
||||
v20.10.2.20-stable 2020-10-23
|
||||
v20.9.5.5-stable 2020-11-13
|
||||
v20.9.4.76-stable 2020-10-29
|
||||
v20.9.3.45-stable 2020-10-09
|
||||
v20.9.2.20-stable 2020-09-22
|
||||
|
|
56
website/benchmark/hardware/results/xeon_clx_6230r.json
Normal file
56
website/benchmark/hardware/results/xeon_clx_6230r.json
Normal file
@ -0,0 +1,56 @@
|
||||
[
|
||||
{
|
||||
"system": "2x Intel CLX 6230R",
|
||||
"system_full": "2x Intel CLX 6230R, 384 GB RAM, P4600 1.6 TB ext4",
|
||||
"cpu_vendor": "Intel",
|
||||
"cpu_model": "2x Intel CLX 6230R",
|
||||
"time": "2020-11-13 00:00:00",
|
||||
"kind": "server",
|
||||
"result":
|
||||
[
|
||||
[0.016, 0.003, 0.003],
|
||||
[0.042, 0.023, 0.022],
|
||||
[0.036, 0.031, 0.032],
|
||||
[0.083, 0.037, 0.036],
|
||||
[0.125, 0.111, 0.109],
|
||||
[0.206, 0.171, 0.172],
|
||||
[0.027, 0.028, 0.028],
|
||||
[0.021, 0.023, 0.023],
|
||||
[0.232, 0.196, 0.195],
|
||||
[0.260, 0.213, 0.210],
|
||||
[0.142, 0.100, 0.103],
|
||||
[0.141, 0.120, 0.109],
|
||||
[0.318, 0.255, 0.256],
|
||||
[0.394, 0.316, 0.311],
|
||||
[0.345, 0.301, 0.306],
|
||||
[0.332, 0.333, 0.318],
|
||||
[0.782, 0.734, 0.719],
|
||||
[0.494, 0.423, 0.412],
|
||||
[1.502, 1.379, 1.429],
|
||||
[0.094, 0.054, 0.057],
|
||||
[0.860, 0.295, 0.302],
|
||||
[0.978, 0.343, 0.344],
|
||||
[1.767, 0.823, 0.827],
|
||||
[2.214, 0.468, 0.443],
|
||||
[0.258, 0.116, 0.121],
|
||||
[0.142, 0.101, 0.104],
|
||||
[0.254, 0.113, 0.113],
|
||||
[0.860, 0.354, 0.356],
|
||||
[0.729, 0.449, 0.447],
|
||||
[0.846, 0.847, 0.854],
|
||||
[0.322, 0.247, 0.245],
|
||||
[0.582, 0.343, 0.348],
|
||||
[2.110, 2.008, 2.031],
|
||||
[1.417, 1.158, 1.135],
|
||||
[1.360, 1.069, 1.084],
|
||||
[0.377, 0.371, 0.357],
|
||||
[0.228, 0.160, 0.157],
|
||||
[0.092, 0.077, 0.076],
|
||||
[0.053, 0.043, 0.057],
|
||||
[0.423, 0.343, 0.348],
|
||||
[0.051, 0.032, 0.034],
|
||||
[0.023, 0.033, 0.035],
|
||||
[0.015, 0.010, 0.016]
|
||||
]
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user