为什么这个查询不使用索引排序?
Why is this query not using an index sort?
注意: Table/Column/Index名字是编的。
背景
我在弄清楚如何有效地查询我的一个数据库 table 时遇到了一些麻烦(table 有大约一百万行)。有问题的查询涉及一个带有外键的 WHERE
子句和一个带有另一列的 ORDER BY
子句。
数据库在 FK 上生成索引,我在将用于排序的列上创建索引:
CREATE INDEX ab ON a(b);
问题
当我运行查询时FK没有过滤:
EXPLAIN SELECT * FROM a ORDER BY b;
数据库正确使用索引进行排序。我知道这一点是因为此查询 returns:
的结果 (t运行cated)
FROM PUBLIC.A
/* PUBLIC.AB */
ORDER BY 3
/* index sorted */
但是,当查询被修改为在 FK 上进行过滤时:
EXPLAIN SELECT * FROM a WHERE a_fk_id = 3 ORDER BY b
只使用FK索引:
FROM PUBLIC.A
/* PUBLIC.A_FK_INDEX_NAME: A_FK_ID = 3 */
WHERE A_FK_ID = 3
ORDER BY 3
如您所见,仅使用了 FK 索引。
问题
这是怎么回事?
我认为这可能与单独的索引有关,但甚至创建了一个多列索引,如:
CREATE INDEX a_fk_id_b ON a(a_fk_id, b);
没有采取任何措施来解决问题(也没有颠倒索引中这些列的顺序,但我没想到会这样)。
如有任何建议,我们将不胜感激。我绝不是数据库或 SQL 专家,但我很惊讶得到这些结果。也许我只是需要以不同的方式查询这些信息,但我认为这是一个相对简单的案例。
原来答案很简单,虽然不是很明显(至少对我来说不是)。 table FK 和 order 列之间需要有复合索引:
CREATE INDEX a_fk_id_b ON a(a_fk_id, b);
为了让数据库使用该索引而不是生成的 FK 索引,a_fk_id
列需要包含在 ORDER BY
子句中:
EXPLAIN SELECT * FROM a WHERE a_fk_id = 3 ORDER BY a_fk_id, b;
这导致我们的复合索引被用于过滤和排序,如这个截断的解释计划所示:
FROM PUBLIC.A
/* PUBLIC.A_FK_ID_B: A_FK_ID = 3 */
WHERE A_FK_ID = 3
ORDER BY 25, 19
/* index sorted */
注意: Table/Column/Index名字是编的。
背景
我在弄清楚如何有效地查询我的一个数据库 table 时遇到了一些麻烦(table 有大约一百万行)。有问题的查询涉及一个带有外键的 WHERE
子句和一个带有另一列的 ORDER BY
子句。
数据库在 FK 上生成索引,我在将用于排序的列上创建索引:
CREATE INDEX ab ON a(b);
问题
当我运行查询时FK没有过滤:
EXPLAIN SELECT * FROM a ORDER BY b;
数据库正确使用索引进行排序。我知道这一点是因为此查询 returns:
的结果 (t运行cated)FROM PUBLIC.A
/* PUBLIC.AB */
ORDER BY 3
/* index sorted */
但是,当查询被修改为在 FK 上进行过滤时:
EXPLAIN SELECT * FROM a WHERE a_fk_id = 3 ORDER BY b
只使用FK索引:
FROM PUBLIC.A
/* PUBLIC.A_FK_INDEX_NAME: A_FK_ID = 3 */
WHERE A_FK_ID = 3
ORDER BY 3
如您所见,仅使用了 FK 索引。
问题
这是怎么回事?
我认为这可能与单独的索引有关,但甚至创建了一个多列索引,如:
CREATE INDEX a_fk_id_b ON a(a_fk_id, b);
没有采取任何措施来解决问题(也没有颠倒索引中这些列的顺序,但我没想到会这样)。
如有任何建议,我们将不胜感激。我绝不是数据库或 SQL 专家,但我很惊讶得到这些结果。也许我只是需要以不同的方式查询这些信息,但我认为这是一个相对简单的案例。
原来答案很简单,虽然不是很明显(至少对我来说不是)。 table FK 和 order 列之间需要有复合索引:
CREATE INDEX a_fk_id_b ON a(a_fk_id, b);
为了让数据库使用该索引而不是生成的 FK 索引,a_fk_id
列需要包含在 ORDER BY
子句中:
EXPLAIN SELECT * FROM a WHERE a_fk_id = 3 ORDER BY a_fk_id, b;
这导致我们的复合索引被用于过滤和排序,如这个截断的解释计划所示:
FROM PUBLIC.A
/* PUBLIC.A_FK_ID_B: A_FK_ID = 3 */
WHERE A_FK_ID = 3
ORDER BY 25, 19
/* index sorted */