2015-12-05 42 views
2

当在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库中打开一个为两个列为连接表添加一个索引的bug,但现在我不太确定。任何人都可以帮助我理解为什么这两种情况下的行为类似,如果有什么差别,那究竟会有什么区别?

+0

这个问题本质上是DBMS特有的。您需要使用相关的DBMS进行标记。 –

+0

感谢您的建议。我加了标签。 –

回答

4
  • 在键列添加NOT NULL约束(如果为空的元组将在这里做没有意义)
  • 添加主键(强制UNIQUE索引上的两个KeyFields中)
  • 至于询问服务FK查找:以相反的顺序
  • 添加复合索引的PK场创建/加入的PK和索引后,您可能要分析表(仅键列有统计)

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%,假设不是NULL)

+0

这是如何回答我的问题? –

+0

你的问题背后的问题是缺乏基本的表结构。 – wildplasser

+0

我这样做了,我在EXPLAIN上得到完全相同的答案。另外,我的问题是为什么会发生这种行为,它背后的逻辑是什么。 –