【问题标题】:Multi-column performance of IN clause + ORDER BYIN子句+ORDER BY的多列表现
【发布时间】:2016-03-21 01:10:56
【问题描述】:

我有一张这样的桌子:

id | person_id | created_at
---------------------------
0  | 10        | ...
1  | 10        | ...
2  | 11        | ...
3  | 11        | ...
.. | ...       | ... 

我目前正在执行以下查询:

SELECT * FROM table WHERE person_id IN (10,11,12,34,58) ORDER BY created_at DESC LIMIT x OFFSET y;

我基本上想要按created_at 排序的记录,但只需要与提供的任何person_id 值相对应的记录。

是的,我有两个独立的索引:created_atperson_id,我一直在问自己以下问题:

  • 我应该创建一个像(created_at, person_id) 这样的多列索引吗?我试图想象它是如何工作的,我认为它仍然会进行顺序扫描(即它的数据按 `created_at 排序,它会逐个记录收集匹配的数据)
  • 我应该像 (person_id, created_at) 那样做吗?

如果我的查询是 WHERE person_id = 10 而不是 IN,我确信 (person_id, created_at) 可以解决问题,但在这种情况下我不能 100% 确定。

【问题讨论】:

  • 你也可以只有 2 个索引 - 每列一个
  • 这完全取决于数据的选择性和许多其他因素。您应该使用 2 个单独的索引和一个在 (person_id, created_at) 上(按此顺序),并使用 EXPLAIN ANALYZE {yourquery} 自己查看 Postgres 使用哪种方法更好的执行计划。
  • 使用explain (analyze, verbose, buffers)检查执行计划

标签: database postgresql indexing


【解决方案1】:

简短回答: (created_at) 上的索引很可能是最佳选择。

长答案:

  • 首先对基本关系应用选择过滤器(即WHERE person_id IN 子句),然后对create_at 列上的数据进行排序,从而评估查询。

  • (created_at, person_id) 索引不太可能有帮助。这样的索引会在 create_at 列上对整个数据集进行排序,并且不允许在 person_id 列上有效地应用选择。确实,查询可以对索引进行更有效的顺序扫描,而不是扫描基本关系,并且符合条件的数据是已经排序的顺序。但是,当您选择所有属性(select * 子句)时,仍需要访问基表以检索每个结果元组的 id 属性。

  • A(person_id 索引)更有可能提高性能,尤其是当您只对少数几个 person_id 感兴趣时。这是因为仅通过在索引中查找值(无基表或索引扫描)就可以有效地应用person_id 上的选择。随着选择谓词的限制较少(当您提供越来越多的 ID 并且越来越多的行通过 where 子句过滤器时),此类索引的好处会降低。

  • A (person_id, created_at) 可能会更有帮助,因为每个符合条件的 person_id 的数据已经排序。 create_at 上的最终排序操作理论上可以优化以利用部分排序的结果元组。但是,并非所有数据库引擎都支持这种优化,如果每个 person_id 只有几个结果元组,它们就不值得了。如果给定的 person_id 有许多条目(可以说超过数百到数千),则将 created_at 添加到索引的好处会更大。

  • 向索引添加更多列并不总是一个好主意,因为您会增加索引的大小及其维护成本。如果create-at 是索引的一部分,则对该列的更新还会在对基本关系的更新之上触发索引更新。

【讨论】:

    猜你喜欢
    • 2016-04-03
    • 2011-10-12
    • 2021-07-20
    • 2019-11-29
    • 2021-07-06
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多