连接表上的索引
Indexes on join tables
在 Google 上搜索 join table indexes 时,我得到 this question.
现在,我认为它在接受的答案中提供了一些虚假信息,或者我不明白一切是如何运作的。
给定以下 tables(运行 on 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 table 的两列上创建索引来复制上述问题中的场景然后为每一列创建一个索引(不保留两列的索引)。
当对正常的传统 select 使用 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 库中打开一个错误,该错误为连接 tables 的两列添加一个索引,但现在我不太确定。谁能帮我理解为什么这两种情况下的行为相似,如果有的话,实际上有什么区别?
- 在键列上添加一个 NOT NULL 约束(带有 NULL 的元组在这里没有意义)
- 添加一个 PRIMARY KEY(在两个键字段上强制使用 UNIQUE 索引)
- 作为 FK 查找的支持:为 PK 字段添加复合索引以相反的顺序
- 在 creating/adding 个主键和索引之后,您可能需要分析 table(只有键列有统计信息)
CREATE TABLE albums_artists
( album_id integer NOT NULL REFERENCES albums (album_id)
, artist_id integer NOT NULL REFERENCES artists (artist_id)
, PRIMARY KEY (album_id, artist_id)
);
CREATE UNIQUE INDEX ON albums_artists (artist_id, album_id);
观察到的行为背后的原因是 planner/optimiser 是 基于信息的 ,受启发式驱动。在没有任何关于给定条件 实际需要的行的比例 或实际加工的行的比例(在 JOIN 的情况下)的任何信息的情况下,规划器做出猜测:(例如:范围查询为 10%)。对于小型查询,哈希连接始终是一个成功的方案,它确实意味着从两个 table 中获取所有元组,但连接本身非常有效。
对于作为键或索引一部分的列,将收集统计信息,因此规划器可以对涉及的行数做出更实际的估计。这通常会导致索引计划,因为这可能需要获取更少的页面。
外键是一种非常特殊的情况;因为计划者将 知道 所有 来自参考 table 的值将出现在参考 table 中。 (即 100%,假设 NOT NULL)
在 Google 上搜索 join table indexes 时,我得到 this question.
现在,我认为它在接受的答案中提供了一些虚假信息,或者我不明白一切是如何运作的。 给定以下 tables(运行 on 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 table 的两列上创建索引来复制上述问题中的场景然后为每一列创建一个索引(不保留两列的索引)。
当对正常的传统 select 使用 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 库中打开一个错误,该错误为连接 tables 的两列添加一个索引,但现在我不太确定。谁能帮我理解为什么这两种情况下的行为相似,如果有的话,实际上有什么区别?
- 在键列上添加一个 NOT NULL 约束(带有 NULL 的元组在这里没有意义)
- 添加一个 PRIMARY KEY(在两个键字段上强制使用 UNIQUE 索引)
- 作为 FK 查找的支持:为 PK 字段添加复合索引以相反的顺序
- 在 creating/adding 个主键和索引之后,您可能需要分析 table(只有键列有统计信息)
CREATE TABLE albums_artists
( album_id integer NOT NULL REFERENCES albums (album_id)
, artist_id integer NOT NULL REFERENCES artists (artist_id)
, PRIMARY KEY (album_id, artist_id)
);
CREATE UNIQUE INDEX ON albums_artists (artist_id, album_id);
观察到的行为背后的原因是 planner/optimiser 是 基于信息的 ,受启发式驱动。在没有任何关于给定条件 实际需要的行的比例 或实际加工的行的比例(在 JOIN 的情况下)的任何信息的情况下,规划器做出猜测:(例如:范围查询为 10%)。对于小型查询,哈希连接始终是一个成功的方案,它确实意味着从两个 table 中获取所有元组,但连接本身非常有效。
对于作为键或索引一部分的列,将收集统计信息,因此规划器可以对涉及的行数做出更实际的估计。这通常会导致索引计划,因为这可能需要获取更少的页面。
外键是一种非常特殊的情况;因为计划者将 知道 所有 来自参考 table 的值将出现在参考 table 中。 (即 100%,假设 NOT NULL)