CTE优化

时间:2013-12-05 15:22:09

标签: postgresql common-table-expression

我最近注意到包含CTE的性能较差的查询。

从运行EXPLAIN开始,如果我在CTE中有2个连续的表,第一个应用了WHERE过滤器,则postgres优化器实际上不会限制行设置,并且所以第二个表查找非常慢:

WITH thing_data AS (
    SELECT * FROM things WHERE id = '0000000001'
), thing_readings AS (
    SELECT  thing_timestamp
    FROM reading_log_instantaneous_schedule
    INNER JOIN thing_data
    ON thing_id = thing_data.id
    ORDER BY thing_timestamp DESC LIMIT 1
),                   
SELECT thing_data.*
FROM thing_data
LEFT OUTER JOIN thing_readings
ON thing_data.id = thing_readings.thing_id 

基本上,读数表中的内部联接并没有从INNER JOIN thing_data on thing_id = thing_data.id中受益,并且实际上正在对阅读表中的所有行进行扫描。

是否有可能让优化器注意到我已将thing_data记录集限制为仅一行,因此使后续加入快速而非超慢?

编辑:对匿名查询不好的道歉。

我创建了一个SQLFiddle来演示我遇到的问题 - 我仍然需要添加2个WHERE子句(不利于代码可维护性等) - 即使忘记了CTE并使用常规连接表,问题仍然存在克雷格建议道。我更习惯于在转换模式时没有出现此问题的SQL Server。

http://sqlfiddle.com/#!15/17c82/1

1 个答案:

答案 0 :(得分:4)

  

是否有可能让优化器注意到我已将thing_data记录集限制为仅一行,因此使后续连接快速而非超慢?

不在PostgreSQL中,至少在9.4或更早版本中。希望以后会改变。

PostgreSQL中的CTE是优化围栏 - 实质上,规划者不能将限定符推入其中,或者将限定符拉出来。

如果这是一个问题,你需要回到使用旧式FROM子句中的子查询。

SELECT thing_data.*
FROM (
    SELECT * FROM things WHERE id = '0000000001'
) data_thing
LEFT OUTER JOIN (
    SELECT  thing_timestamp 
    FROM reading_log_instantaneous_schedule 
    INNER JOIN thing_data on thing_id = thing_data.id 
    ORDER BY thing_timestamp DESC LIMIT 1)
thing_readings 
ON thing_data.id = thing_readings.thing_id;

因为FROM 中的子查询允许限定符下推/上拉。但是,在这种情况下,您确实希望横向应用WHERE子句。这最好通过进一步简化,摆脱子查询来完成:

SELECT thing_data.*
FROM things
LEFT OUTER JOIN (
    SELECT  thing_timestamp 
    FROM reading_log_instantaneous_schedule 
    INNER JOIN thing_data on thing_id = thing_data.id 
    ORDER BY thing_timestamp DESC LIMIT 1)
thing_readings 
ON thing_data.id = thing_readings.thing_id
WHERE things.id = '0000000001'

但是,整个过程似乎是一种非常复杂的方式(基于您的SQLFiddle http://sqlfiddle.com/#!15/17c82/3):

SELECT  things.*, thingreadings.reading 
FROM things 
LEFT OUTER JOIN thingreadings ON thingreadings.thingid = things.id
WHERE things.id = '1'
ORDER BY reading DESC LIMIT 1;
相关问题