添加LIMIT子句时,简单查询会慢得多

时间:2014-04-08 03:55:21

标签: sql postgresql limit

我有一张桌子(snmp陷阱,但那里既不存在也不存在)。

我有一个查询可以提取一些记录,如下所示:

SELECT * 
FROM traps_trap 
WHERE summary_id = 1600
ORDER BY traps_trap."trapTime";

这会立即响应,有6条记录。

当我添加LIMIT 50时(因为并非所有结果都只有6条记录),它非常非常缓慢(至于根本不返回)。

summary_id列上有一个索引,我只能假设它没有被用于第二个查询。

我知道解决此问题的工具是explain,但我对它的理解结果不够熟悉。

解释分析第一个(快速)查询的详细信息如下:

                                                                   QUERY PLAN                                                                       
--------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=14491.51..14502.48 rows=4387 width=263) (actual time=0.128..0.130 rows=6 loops=1)
   Output: id, summary_id, "trapTime", packet
   Sort Key: traps_trap."trapTime"
   Sort Method: quicksort  Memory: 28kB
   ->  Index Scan using traps_trap_summary_id on public.traps_trap  (cost=0.00..13683.62 rows=4387 width=263) (actual time=0.060..0.108 rows=6 loops=1)
         Output: id, summary_id, "trapTime", packet
         Index Cond: (traps_trap.summary_id = 1600)
 Total runtime: 0.205 ms
(8 rows)

解释第二个是:

                                               QUERY PLAN                                                
---------------------------------------------------------------------------------------------------------
  Limit  (cost=0.00..2538.69 rows=10 width=263)
   ->  Index Scan using "traps_trap_trapTime" on traps_trap  (cost=0.00..1113975.68 rows=4388 width=263)
         Filter: (summary_id = 1600)
(3 rows)

我每天都会运行VACUUMANALYZE,我知道应该会改进计划。还有其他指针吗?

1 个答案:

答案 0 :(得分:1)

使用trapTime的索引扫描比使用summary_id的索引扫描慢得多。 我会尝试嵌套查询(使用计划#1):

select * from (
    SELECT * 
    FROM traps_trap 
    WHERE summary_id = 1600
    ORDER BY traps_trap."trapTime"
) t
limit 50;

编辑:

在做了一些测试后,我了解到简单的查询嵌套(如上所述)对规划器没有影响。 要强制规划人员使用traps_trap_summary_id索引,您可以使用CTE(我的测试确认此方法):

with t as (
    SELECT * 
    FROM traps_trap 
    WHERE summary_id = 1600
    ORDER BY traps_trap."trapTime"
)
select * from t
limit 50;