SQL 查询 order by 和 limit 需要花费大量时间

问题描述 投票:0回答:3

我正在查询一张包含大约 4M 数据和两种类型 skuID 的表,并在版本上使用 order by,因为一个 skuID 大约有平均 5k 个版本的数据,并使用 limit 获取最高版本。

查询:

 select * FROM table rb 
    WHERE rb.sku_id='' or rb.package_sku_id=''
    order by version desc
limit 1;

通过对查询使用解释,我们发现 ORDER BY 和 LIMIT 占用了查询的大部分成本:

Limit  (cost=0.43..5304.64 rows=1 width=861) (actual time=50327.036..50327.041 rows=1 loops=1)
  Buffers: shared hit=361280 read=104302 written=18
  I/O Timings: read=40363.693 write=0.215
  ->  Index Scan Backward using "IDX488yr43nr28a1yml9lb5i7jfv" on referral_benefits rb  (cost=0.43..9552890.48 rows=1801 width=861) (actual time=50327.028..50327.028 rows=1 loops=1)
        Filter: (((sku_id)::text = 'b1d5fa77-fda8-466c-b8b0-a8e60d1f78a5'::text) OR ((package_sku_id)::text = 'b1d5fa77-fda8-466c-b8b0-a8e60d1f78a5'::text))
        Rows Removed by Filter: 1361027
        Buffers: shared hit=361280 read=104302 written=18
        I/O Timings: read=40363.693 write=0.215
Planning Time: 1.121 ms
Execution Time: 50329.843 ms

我们在 skuId 和 package_sku_id 上添加了组合索引,但这并没有减少时间。

需要这方面的指导。 预先感谢

sql postgresql backend
3个回答
1
投票

如果您有两个索引,一个在

(sku_id, version)
上,一个在
(package_sku_id, version)
上,那么您可以通过执行以下操作来获得非常快的执行速度:

(select * FROM rb WHERE rb.sku_id='b1d5fa77-fda8-466c-b8b0-a8e60d1f78a5' order by version desc) 
    union all
(select * FROM rb WHERE rb.package_sku_id='b1d5fa77-fda8-466c-b8b0-a8e60d1f78a5' order by version desc)
order by version desc limit 1;

但请注意,如果将 LIMIT 增加到超过 1,则当同一行满足两个 SKU 条件时,此查询可能会返回重复行。


1
投票

PostgreSQL 具有部分索引,即仅适用于表的子集的索引。使用该索引类型并让它仅包含您想要查看的行。然后 DBMS 只需读取该索引,数据就会排序:

create index idx on mytable (version desc)
                 where sku_id = '' or package_sku_id = '';

另一个选项是一个单独的表,仅包含所需的顶行。编写一个触发器以使其保持最新状态。


0
投票

请求中有 3 列用于过滤(sku_id、package_sku_id、版本)。所以真正有用的是 3 列的组合索引。 1 列上的单独索引对于此请求没有多大效果。

create index idx on rb (sku_id, package_sku_id, version)

© www.soinside.com 2019 - 2024. All rights reserved.