我正在查询一张包含大约 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 上添加了组合索引,但这并没有减少时间。
需要这方面的指导。 预先感谢
如果您有两个索引,一个在
(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 条件时,此查询可能会返回重复行。
PostgreSQL 具有部分索引,即仅适用于表的子集的索引。使用该索引类型并让它仅包含您想要查看的行。然后 DBMS 只需读取该索引,数据就会排序:
create index idx on mytable (version desc)
where sku_id = '' or package_sku_id = '';
另一个选项是一个单独的表,仅包含所需的顶行。编写一个触发器以使其保持最新状态。
请求中有 3 列用于过滤(sku_id、package_sku_id、版本)。所以真正有用的是 3 列的组合索引。 1 列上的单独索引对于此请求没有多大效果。
create index idx on rb (sku_id, package_sku_id, version)