在Google上搜索加入表索引时,我得到了this question。
现在,我相信它在接受的答案中提供了一些虚假信息,或者我不明白一切是如何运作的。 给出以下表格(在PostGreSQL 9.4上运行):
CREATE TABLE "albums" ("album_id" serial PRIMARY KEY, "album_name" text)
CREATE TABLE "artists" ("artist_id" serial PRIMARY KEY, "artist_name" text)
CREATE TABLE "albums_artists" ("album_id" integer REFERENCES "albums", "artist_id" integer REFERENCES "artists")
我试图从上面提到的问题复制场景,首先在 albums_artists 表的两列上创建索引,然后为每列创建一个索引(不保留索引)两列)。
对于普通的传统选择使用EXPLAIN命令时,我会期待非常不同的结果,如下所示:
SELECT "artists".* FROM "test"."artists"
INNER JOIN "test"."albums_artists" ON ("albums_artists"."artist_id" = "artists"."artist_id")
WHERE ("albums_artists"."album_id" = 1)
然而,当实际运行解释时,我得到的结果完全相同(每列有一个索引,两列有一个索引)。
我一直在阅读关于PostGreSQL的关于索引的文档,它对我得到的结果没有任何意义:
Hash Join (cost=15.05..42.07 rows=11 width=36) (actual time=0.024..0.025 rows=1 loops=1)
Hash Cond: (artists.artist_id = albums_artists.artist_id)
-> Seq Scan on artists (cost=0.00..22.30 rows=1230 width=36) (actual time=0.006..0.006 rows=1 loops=1)
-> Hash (cost=14.91..14.91 rows=11 width=4) (actual time=0.009..0.009 rows=1 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 1kB
-> Bitmap Heap Scan on albums_artists (cost=4.24..14.91 rows=11 width=4) (actual time=0.008..0.009 rows=1 loops=1)
Recheck Cond: (album_id = 1)
Heap Blocks: exact=1
-> Bitmap Index Scan on albums_artists_album_id_index (cost=0.00..4.24 rows=11 width=0) (actual time=0.005..0.005 rows=1 loops=1)
Index Cond: (album_id = 1)
我希望在使用由2个不同列组成的索引时,不会在最后一步获得索引扫描(因为我只在 WHERE 子句中使用其中一个)。
我打算在ORM库中打开一个错误,为连接表的两列添加一个索引,但现在我不太确定。任何人都可以帮助我理解为什么两种情况下的行为相似,实际上有什么区别,如果有的话?
答案 0 :(得分:6)
CREATE TABLE albums_artists
( album_id integer NOT NULL REFERENCES albums
, artist_id integer NOT NULL REFERENCES artists
, PRIMARY KEY (album_id, artist_id)
);
CREATE UNIQUE INDEX ON albums_artists (artist_id, album_id);
观察到的行为背后的原因是规划器/优化器是基于信息的,由启发式驱动。如果没有任何关于实际需要的行分数的信息给定条件,或者实际匹配的行的比例(在JOIN的情况下),计划者会猜测:(例如:范围查询的10%)。对于小型查询,散列连接将始终是获胜方案,它确实意味着从两个表中获取所有元组,但连接本身非常有效。
对于属于键或索引的列,将收集统计信息,以便规划人员可以对所涉及的行数进行更实际的估算。 Ald通常会导致索引计划,因为这可能需要更少的页面被提取。
外键是一个非常特殊的情况;由于计划程序知道 所有,引用表中的值将出现在引用表中。 (即100%,假设NOT NULL)