【问题标题】:How can I get a postgres query with an ORDER BY to do an index only scan?如何获取带有 ORDER BY 的 postgres 查询以进行仅索引扫描?
【发布时间】:2018-08-26 19:40:14
【问题描述】:

我有一个相当大的表,其中最常见的 API 请求是这样的:

/api/orders?status=confirmed

为服务该请求而生成的实际 SQL 类似于:

SELECT * FROM orders 
WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL 
ORDER BY int_id;

在我的一生中,我无法弄清楚在 postgres 9.5.4 上运行的索引会使其表现得非常好。

我在(account_id, status, versionID) 上创建了一个索引,这使得在同一个查询中减去ORDER BY(它使用“仅索引扫描”),事情变得非常快,但是一旦ORDER BY 在那里,它就会恢复回到“位图堆扫描”和“位图索引扫描”的组合,速度要慢 50-100 倍。

我还尝试在(int_id ASC, account_id, status, versionID) 上创建索引,查询规划器似乎完全忽略了它。

关于如何使用“仅索引扫描”或同等快速的方法构建将服务于完整查询的索引的任何想法?

【问题讨论】:

  • 你确定这是完整的故事吗?你能发布一些架构吗?我似乎无法复制您的问题:create table orders (orders_id serial primary key, account_id text not null, status text not null, version_id int null); insert into orders (account_id, status, version_id) select generate_series(1, 100000), 'confirmed', null; SELECT * FROM orders WHERE account_id = '1' AND status = 'confirmed' AND version_id IS NULL ORDER BY orders_id; 给了我一个仅索引扫描。

标签: sql postgresql indexing


【解决方案1】:

如果你知道 where 子句过滤器是一致的,你可以在包含静态过滤器的情况下使索引更小:

CREATE INDEX test_idx1 ON orders (account_id, int_id ASC NULLS LAST) WHERE status = 'confirmed' AND versionID IS NULL

该索引将包含按 int_id 排序的每个帐户。我发现将 ORDER BY 显式设置为与索引相同会很有帮助,因此您可以证明它正在工作:

SELECT * FROM orders WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL ORDER BY int_id ASC NULLS LAST;

如果您可以从 SELECT * 更改为列列表,您还可以做得更好:

SELECT address, name FROM orders WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL ORDER BY int_id;

那么这应该做一个仅索引扫描:

CREATE INDEX test_idx2 ON orders (account_id, int_id, address, name) WHERE AND status = 'confirmed' AND versionID IS NULL

【讨论】:

    【解决方案2】:

    对于这个查询:

    SELECT o.*
    FROM orders o
    WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL 
    ORDER BY int_id;
    

    最佳索引是(account_id, status, versionID, int_id) 上的复合索引。 int_id 应该是索引中的最后一个键,因为 order by 应该在 where 子句中的过滤之后发生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-24
      • 2022-01-16
      • 1970-01-01
      • 2013-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多