我有一张这样的表:
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_at
和person_id
,我一直在问自己以下内容:
(created_at, person_id)
这样的多列索引吗?我试图想象它是如何工作的,我认为它仍然会进行顺序扫描(即它的数据按`created_at排序,它会记录收集匹配的记录)(person_id, created_at)
那样做吗?如果我的查询是WHERE person_id = 10
而不是IN
,我确定(person_id, created_at)
可以解决问题,但我不能100%确定场景。
答案 0 :(得分:1)
简答:(created_at
)上的索引最有可能是最佳选择。
答案很长:
通过首先对基本关系(即WHERE person_id IN
子句)应用选择过滤器,然后对create_at
列上的数据进行排序来评估查询。
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
是索引的一部分,则对此列的更新还会触发基础关系更新之上的索引更新。