【问题标题】:Simple query gets much slower when I add a LIMIT clause当我添加 LIMIT 子句时,简单查询变得慢得多
【发布时间】:2014-04-08 03:55:20
【问题描述】:

我有一个表(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,我知道这应该可以改进计划。有其他指针吗?

【问题讨论】:

  • 尝试在列上创建多列索引:summary_id + trapTime(summary_id 必须是索引中的第一列)。

标签: sql postgresql limit


【解决方案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;

【讨论】:

    猜你喜欢
    • 2020-11-21
    • 1970-01-01
    • 2012-01-06
    • 2021-12-30
    • 2021-08-26
    • 2014-09-13
    • 2020-12-30
    • 2022-12-14
    • 1970-01-01
    相关资源
    最近更新 更多