analyzer - apply limit and offset settings

This commit is contained in:
Yakov Olkhovskiy 2023-02-21 03:29:14 +00:00
parent b0424c1021
commit ce2b044532
5 changed files with 102 additions and 6 deletions

View File

@ -233,6 +233,17 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q
auto select_settings = select_query_typed.settings();
SettingsChanges settings_changes;
if (is_subquery)
{
if (const Settings & settings_ref = updated_context->getSettingsRef(); settings_ref.limit || settings_ref.offset)
{
Settings settings = updated_context->getSettings();
settings.limit = 0;
settings.offset = 0;
updated_context->setSettings(settings);
}
}
if (select_settings)
{
auto & set_query = select_settings->as<ASTSetQuery &>();

View File

@ -216,12 +216,17 @@ public:
limit_length = query_node.getLimit()->as<ConstantNode &>().getValue().safeGet<UInt64>();
}
if (settings.limit)
limit_length = limit_length ? std::min(limit_length, settings.limit.value) : settings.limit;
if (query_node.hasOffset())
{
/// Constness of offset is validated during query analysis stage
limit_offset = query_node.getOffset()->as<ConstantNode &>().getValue().safeGet<UInt64>();
}
limit_offset += settings.offset;
/// Partial sort can be done if there is LIMIT, but no DISTINCT, LIMIT WITH TIES, LIMIT BY, ARRAY JOIN
if (limit_length != 0 &&
!query_node.isDistinct() &&
@ -720,7 +725,7 @@ bool addPreliminaryLimitOptimizationStepIfNeeded(QueryPlan & query_plan,
bool apply_limit = query_processing_info.getToStage() != QueryProcessingStage::WithMergeableStateAfterAggregation;
bool apply_prelimit = apply_limit &&
query_node.hasLimit() &&
query_analysis_result.limit_length &&
!query_node.isLimitWithTies() &&
!query_node.isGroupByWithTotals() &&
!query_analysis_result.query_has_with_totals_in_any_subquery_in_join_tree &&
@ -767,7 +772,7 @@ void addPreliminarySortOrDistinctOrLimitStepsIfNeeded(QueryPlan & query_plan,
* Otherwise we can take several equal values from different streams
* according to limit and skip some distinct values.
*/
if (query_node.hasLimit() && query_node.isDistinct())
if (query_analysis_result.limit_length && query_node.isDistinct())
{
addDistinctStep(query_plan,
query_analysis_result,
@ -785,7 +790,7 @@ void addPreliminarySortOrDistinctOrLimitStepsIfNeeded(QueryPlan & query_plan,
addLimitByStep(query_plan, limit_by_analysis_result, query_node);
}
if (query_node.hasLimit())
if (query_analysis_result.limit_length)
addPreliminaryLimitStep(query_plan, query_analysis_result, planner_context, true /*do_not_skip_offset*/);
}
@ -1420,7 +1425,7 @@ void Planner::buildPlanForQueryNode()
bool apply_offset = query_processing_info.getToStage() != QueryProcessingStage::WithMergeableStateAfterAggregationAndLimit;
if (query_node.hasLimit() && query_node.isLimitWithTies() && apply_offset)
if (query_analysis_result.limit_length && query_node.isLimitWithTies() && apply_offset)
addLimitStep(query_plan, query_analysis_result, planner_context, query_node);
addExtremesStepIfNeeded(query_plan, planner_context);
@ -1434,9 +1439,9 @@ void Planner::buildPlanForQueryNode()
* This is the case for various optimizations for distributed queries,
* and when LIMIT cannot be applied it will be applied on the initiator anyway.
*/
if (query_node.hasLimit() && apply_limit && !limit_applied && apply_offset)
if (query_analysis_result.limit_length && apply_limit && !limit_applied && apply_offset)
addLimitStep(query_plan, query_analysis_result, planner_context, query_node);
else if (!limit_applied && apply_offset && query_node.hasOffset())
else if (!limit_applied && apply_offset && query_analysis_result.limit_length)
addOffsetStep(query_plan, query_analysis_result);
/// Project names is not done on shards, because initiator will not find columns in blocks

View File

@ -95,6 +95,8 @@ ContextPtr getViewContext(ContextPtr context)
view_settings.max_result_rows = 0;
view_settings.max_result_bytes = 0;
view_settings.extremes = false;
view_settings.limit = 0;
view_settings.offset = 0;
view_context->setSettings(view_settings);
return view_context;
}

View File

@ -0,0 +1,54 @@
-- { echoOn }
SET limit = 0;
SELECT * FROM numbers(10);
0
1
2
3
4
5
6
7
8
9
SELECT * FROM numbers(10) SETTINGS limit=5, offset=2;
2
3
4
5
6
SELECT count(*) FROM (SELECT * FROM numbers(10));
10
SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5);
5
SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5;
10
SELECT count(*) FROM view(SELECT * FROM numbers(10));
10
SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5);
5
SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5;
10
SET limit = 3;
SELECT * FROM numbers(10);
0
1
2
SELECT * FROM numbers(10) SETTINGS limit=5, offset=2;
2
3
4
5
6
SELECT count(*) FROM (SELECT * FROM numbers(10));
10
SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5);
5
SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5;
10
SELECT count(*) FROM view(SELECT * FROM numbers(10));
10
SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5);
5
SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5;
10

View File

@ -0,0 +1,24 @@
SET allow_experimental_analyzer = 1;
-- { echoOn }
SET limit = 0;
SELECT * FROM numbers(10);
SELECT * FROM numbers(10) SETTINGS limit=5, offset=2;
SELECT count(*) FROM (SELECT * FROM numbers(10));
SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5);
SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5;
SELECT count(*) FROM view(SELECT * FROM numbers(10));
SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5);
SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5;
SET limit = 3;
SELECT * FROM numbers(10);
SELECT * FROM numbers(10) SETTINGS limit=5, offset=2;
SELECT count(*) FROM (SELECT * FROM numbers(10));
SELECT count(*) FROM (SELECT * FROM numbers(10) SETTINGS limit=5);
SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5;
SELECT count(*) FROM view(SELECT * FROM numbers(10));
SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5);
SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5;
-- { echoOff }