IN子句+ ORDER BY的多列性能

时间:2015-12-15 09:52:56

标签: database postgresql indexing

我有一张这样的表:

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%确定场景。

1 个答案:

答案 0 :(得分:1)

简答:created_at)上的索引最有可能是最佳选择。

答案很长:

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

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

  • A(person_id索引)更有可能提高性能,尤其是如果您只对少数person_ids感兴趣的话。这是因为仅通过查找索引中的值(无基表或索引扫描)就可以有效地应用person_id上的选择。这样的索引的好处随着选择谓词的限制性降低而减少(因为你提供了越来越多的ID,并且更大比例的行通过了where子句过滤器)。

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

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