This commit is contained in:
yariks5s 2023-11-03 16:47:06 +00:00
parent 7e4742f68a
commit d95262622b
7 changed files with 159 additions and 3 deletions

View File

@ -3954,6 +3954,17 @@ Possible values:
Default value: `''`.
## preferred_optimize_projection_name {#preferred_optimize_projection_name}
If it is set to a non-empty string, ClickHouse will try to apply specified projection in query.
Possible values:
- string: name of preferred projection
Default value: `''`.
## alter_sync {#alter-sync}
Allows to set up waiting for actions to be executed on replicas by [ALTER](../../sql-reference/statements/alter/index.md), [OPTIMIZE](../../sql-reference/statements/optimize.md) or [TRUNCATE](../../sql-reference/statements/truncate.md) queries.

View File

@ -605,6 +605,7 @@ class IColumn;
M(Bool, optimize_use_implicit_projections, true, "Automatically choose implicit projections to perform SELECT query", 0) \
M(Bool, force_optimize_projection, false, "If projection optimization is enabled, SELECT queries need to use projection", 0) \
M(String, force_optimize_projection_name, "", "If it is set to a non-empty string, check that this projection is used in the query at least once.", 0) \
M(String, preferred_optimize_projection_name, "", "If it is set to a non-empty string, ClickHouse tries to apply specified projection", 0) \
M(Bool, async_socket_for_remote, true, "Asynchronously read from socket executing remote query", 0) \
M(Bool, async_query_sending_for_remote, true, "Asynchronously create connections and send query to shards in remote query", 0) \
M(Bool, insert_null_as_default, true, "Insert DEFAULT values instead of NULL in INSERT SELECT (UNION ALL)", 0) \

View File

@ -42,6 +42,7 @@ struct QueryPlanOptimizationSettings
bool optimize_projection = false;
bool force_use_projection = false;
String force_projection_name;
String preferred_projection_name;
bool optimize_use_implicit_projections = false;
static QueryPlanOptimizationSettings fromSettings(const Settings & from);

View File

@ -444,8 +444,33 @@ AggregateProjectionCandidates getAggregateProjectionCandidates(
const auto & projections = metadata->projections;
std::vector<const ProjectionDescription *> agg_projections;
for (const auto & projection : projections)
if (projection.type == ProjectionDescription::Type::Aggregate)
const auto & proj_name_from_settings = context->getSettings().preferred_optimize_projection_name.value;
bool is_projection_found = false;
// Here we iterate over the projections and check if we have the same projections as we specified in preferred_projection_name
if (!proj_name_from_settings.empty())
{
for (const auto & projection : projections)
{
if (projection.type == ProjectionDescription::Type::Aggregate)
{
size_t last_dot_pos = projection.name.find_last_of('.');
std::string projection_name = (last_dot_pos != std::string::npos) ? projection.name.substr(last_dot_pos + 1) : projection.name;
if (proj_name_from_settings == projection_name)
{
agg_projections.push_back(&projection);
is_projection_found = true;
break;
}
}
}
if (!is_projection_found)
throw Exception(ErrorCodes::INCORRECT_DATA, "Projection {} is specified in setting force_optimize_projection_name but not used",
proj_name_from_settings);
}
else
for (const auto & projection : projections)
agg_projections.push_back(&projection);
bool can_use_minmax_projection = allow_implicit_projections && metadata->minmax_count_projection

View File

@ -7,6 +7,8 @@
#include <Processors/QueryPlan/ReadFromPreparedSource.h>
#include <Processors/Sources/NullSource.h>
#include <Common/logger_useful.h>
#include <Storages/ProjectionsDescription.h>
#include <Storages/SelectQueryInfo.h>
#include <Storages/MergeTree/MergeTreeDataSelectExecutor.h>
#include <stack>
@ -131,6 +133,26 @@ bool optimizeUseNormalProjections(Stack & stack, QueryPlan::Nodes & nodes)
std::shared_ptr<PartitionIdToMaxBlock> max_added_blocks = getMaxAddedBlocks(reading);
// Here we iterate over the projections and check if we have the same projections as we specified in preferred_projection_name
bool is_projection_found = false;
const auto & proj_name_from_settings = context->getSettings().preferred_optimize_projection_name.value;
if (!proj_name_from_settings.empty())
{
for (const auto * projection : normal_projections)
{
size_t last_dot_pos = projection->name.find_last_of('.');
std::string projection_name = (last_dot_pos != std::string::npos) ? projection->name.substr(last_dot_pos + 1) : projection->name;
if (projection_name == proj_name_from_settings)
{
is_projection_found = true;
break;
}
}
if (!is_projection_found)
throw Exception(ErrorCodes::INCORRECT_DATA, "Projection {} is specified in setting force_optimize_projection_name but not used",
proj_name_from_settings);
}
for (const auto * projection : normal_projections)
{
if (!hasAllRequiredColumns(projection, required_columns))
@ -153,7 +175,12 @@ bool optimizeUseNormalProjections(Stack & stack, QueryPlan::Nodes & nodes)
if (candidate.sum_marks >= ordinary_reading_marks)
continue;
if (best_candidate == nullptr || candidate.sum_marks < best_candidate->sum_marks)
size_t last_dot_pos = projection->name.find_last_of('.');
std::string projection_name = (last_dot_pos != std::string::npos) ? projection->name.substr(last_dot_pos + 1) : projection->name;
if (!is_projection_found && (best_candidate == nullptr || candidate.sum_marks < best_candidate->sum_marks))
best_candidate = &candidate;
else if (is_projection_found && projection_name == proj_name_from_settings)
best_candidate = &candidate;
}

View File

@ -0,0 +1,6 @@
test
projection_test_by_string
Executing query with setting
test
projection_test_by_more
0

View File

@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Tags: no-fasttest
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
$CLICKHOUSE_CLIENT -q "
CREATE TABLE test (
test_id UInt64,
test_name String,
test_count Nullable(Float64),
test_string String,
PROJECTION projection_test_by_string (
SELECT test_string,
sum(test_count)
GROUP BY test_id,
test_string,
test_name
),
PROJECTION projection_test_by_more (
SELECT test_string,
test_name,
sum(test_count)
GROUP BY test_id,
test_string,
test_name
)
) ENGINE = MergeTree
ORDER BY test_string;"
$CLICKHOUSE_CLIENT -q "
INSERT INTO test
SELECT number,
'test',
1.* (number / 2),
'test'
FROM numbers(100, 500);"
$CLICKHOUSE_CLIENT --query_id '02907_test' -q "
SELECT test_string
FROM test
WHERE (test_id > 50)
AND (test_id < 150)
GROUP BY test_string;"
$CLICKHOUSE_CLIENT -q "
SELECT projections
FROM system.query_log
WHERE query_id = '02907_test' AND arrayElement(projections, 1) LIKE '%projection_test_by_string'
LIMIT 1;" | grep -o "projection_test_by_string" || true
$CLICKHOUSE_CLIENT -q "
SELECT projections
FROM system.query_log
WHERE query_id = '02907_test' AND arrayElement(projections, 1) LIKE '%projection_test_by_more'
LIMIT 1;" | grep -o "projection_test_by_more" || true
echo "Executing query with setting"
$CLICKHOUSE_CLIENT --query_id '02907_test_1' --preferred_optimize_projection_name 'projection_test_by_more' -q "
SELECT test_string
FROM test
WHERE (test_id > 50)
AND (test_id < 150)
GROUP BY test_string;"
$CLICKHOUSE_CLIENT -q "
SELECT projections
FROM system.query_log
WHERE query_id = '02907_test_1' AND arrayElement(projections, 1) LIKE '%projection_test_by_more'
LIMIT 1;" | grep -o "projection_test_by_more" || true
$CLICKHOUSE_CLIENT -q "
SELECT projections
FROM system.query_log
WHERE query_id = '02907_test_1' AND arrayElement(projections, 1) LIKE '%projection_test_by_string'
LIMIT 1" | grep -o "projection_test_by_string" || true
$CLICKHOUSE_CLIENT --query_id '02907_test_1' --preferred_optimize_projection_name 'non_existing_projection' -q "
SELECT test_string
FROM test
WHERE (test_id > 50)
AND (test_id < 150)
GROUP BY test_string;" 2>&1 | grep -c "BAD_ARGUMENTS" || true