I’m seeing some unexpected behavior in the number of segments scanned when a query is in a CTE vs. when it’s not in a CTE. I have a query structured like so:
with
filtered_facts as (
select
sum(value) as value,
epoch as epoch,f.metric_id as metric_id,f.app_id as app_id
from facts_app_metrics f
where f.metric_id in (...) and epoch = ... and f.app_id = ...
group by epoch,f.metric_id,f.app_id
)
select
sum(value)
from filtered_facts;
This is a much more simplified version of what I’m trying to do, but it demonstrates the issue. This query has a profile like so:
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PROFILE |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Project [`sum(value)`] actual_rows: 1 exec_time: 0ms start_time: 00:00:00.089 network_traffic: 0.014000 KB network_time: 0ms |
| Aggregate [SUM(remote_0.`sum(value)`) AS `sum(value)`] actual_rows: 48 exec_time: 0ms start_time: 00:00:00.024 |
| Gather partitions:all est_rows:1 alias:remote_0 actual_rows: 48 exec_time: 0ms start_time: 00:00:00.089 end_time: 00:00:00.089 |
| Project [`sum(value)`] est_rows:1 actual_rows: 48 exec_time: 0ms start_time: [00:00:00.023, 00:00:00.087] network_traffic: 0.057000 KB network_time: 0ms |
| Aggregate [SUM(filtered_facts.value) AS `sum(value)`] actual_rows: 12 exec_time: 0ms start_time: 00:00:00.053 |
| TableScan 0tmp AS filtered_facts storage:list stream:yes est_table_rows:62,371,410 exec_time: 0ms |
| Project [value] est_rows:62,371,410 actual_rows: 12 exec_time: 0ms start_time: 00:00:00.053 |
| StreamingGroupBy [SUM(f.value) AS value] groups:[f.metric_id] actual_rows: 12 exec_time: 0ms start_time: 00:00:00.053 memory_usage: 0.000000 KB |
| Filter [f.metric_id IN (...) AND f.epoch = ? AND f.app_id = ?] actual_rows: 1,956 exec_time: 2ms start_time: 00:00:00.051 |
| [actual_rows: 1,956 | max:1,956 at partition_40, average: 40.750000, std dev: 279.367925] |
| OrderedColumnStoreScan report_service.facts_app_metrics AS f, KEY app_id (app_id, epoch, metric_id, device_country_id, store_id) USING CLUSTERED COLUMNSTORE WITH(COLUMNSTORE_SEGMENT_ROWS=102400) est_table_rows:24,948,564,112 est_filtered:62,371,411 actual_rows: 14,745,600 exec_time: 83ms start_time: [00:00:00.001, 00:00:00.026] memory_usage: 37,748.734375 KB segments_scanned: 144 segments_skipped: 256,195 segments_fully_contained: 0 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
If I were to extract the CTE into its own query:
select
sum(value) as value,
epoch as epoch,f.metric_id as metric_id,f.app_id as app_id
from facts_app_metrics f
where f.metric_id in (...) and epoch = ... and f.app_id = ...
group by epoch,f.metric_id,f.app_id;
…you’ll notice it actually scans fewer rows:
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PROFILE |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Gather partitions:single alias:remote_0 actual_rows: 12 exec_time: 0ms |
| Project [value, f.epoch, f.metric_id, f.app_id] actual_rows: 12 exec_time: 0ms start_time: 00:00:00.018 network_traffic: 0.403000 KB network_time: 0ms |
| StreamingGroupBy [SUM(f.value) AS value] groups:[f.metric_id] actual_rows: 12 exec_time: 1ms start_time: 00:00:00.018 memory_usage: 0.000000 KB |
| Filter [f.metric_id IN (...) AND f.epoch = ? AND f.app_id = ?] actual_rows: 1,956 exec_time: 0ms start_time: 00:00:00.016 |
| OrderedColumnStoreScan report_service.facts_app_metrics AS f, KEY app_id (app_id, epoch, metric_id, device_country_id, store_id) USING CLUSTERED COLUMNSTORE WITH(COLUMNSTORE_SEGMENT_ROWS=102400) est_table_rows:24,948,564,112 est_filtered:62,371,411 actual_rows: 307,200 exec_time: 17ms start_time: 00:00:00.001 memory_usage: 786.432007 KB segments_scanned: 3 segments_skipped: 5,335 segments_fully_contained: 0 |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
That seems to indicate a difference of 144 segments being scanned when used in a CTE vs. only 3 segments when not used in a CTE. Am I reading that correctly?
Is there anything we can do in our queries to reduce the segments being scanned when this type of query is used in a CTE?
Thanks!