为什么通过添加索引来增加成本?

Joh*_*ins 1 sql postgresql indexing

我正在使用postgresql 9.4.6.

有以下实体:

CREATE TABLE user (id CHARACTER VARYING NOT NULL PRIMARY KEY);

CREATE TABLE group (id CHARACTER VARYING NOT NULL PRIMARY KEY);

CREATE TABLE group_member (
       id CHARACTER VARYING NOT NULL PRIMARY KEY,
       gid CHARACTER VARYING REFERENCES group(id),
       uid CHARACTER VARYING REFERENCES user(id));
Run Code Online (Sandbox Code Playgroud)

我分析了那个查询:

explain analyze select x2."gid" from "group_member" x2 where x2."uid" = 'a1';
Run Code Online (Sandbox Code Playgroud)

我有几个结果.在每个结果之前,我刷新了操作系统缓存并重新启动了postgres:

# /etc/init.d/postgresql stop
# sync
# echo 3 > /proc/sys/vm/drop_caches
# /etc/init.d/postgresql start
Run Code Online (Sandbox Code Playgroud)

分析结果如下:

1)成本= 4.17..11.28带索引:

create index "group_member_gid_idx" on "group_member" ("gid");
create index "group_member_uid_idx" on "group_member" ("uid");

 Bitmap Heap Scan on group_member x2  (cost=4.17..11.28 rows=3 width=32) (actual time=0.021..0.021 rows=0 loops=1)
   Recheck Cond: ((uid)::text = 'a1'::text)
   ->  Bitmap Index Scan on group_member_uid_idx  (cost=0.00..4.17 rows=3 width=0) (actual time=0.005..0.005 rows=0 loops=1)
         Index Cond: ((uid)::text = 'a1'::text)
 Planning time: 28.641 ms
 Execution time: 0.359 ms
Run Code Online (Sandbox Code Playgroud)

2)成本= 7.97..15.08,有索引:

create unique index "group_member_gid_uid_idx" on "group_member" ("gid","uid");

 Bitmap Heap Scan on group_member x2  (cost=7.97..15.08 rows=3 width=32) (actual time=0.013..0.013 rows=0 loops=1)
   Recheck Cond: ((uid)::text = 'a1'::text)
   ->  Bitmap Index Scan on group_member_gid_uid_idx  (cost=0.00..7.97 rows=3 width=0) (actual time=0.006..0.006 rows=0 loops=1)
         Index Cond: ((uid)::text = 'a1'::text)
 Planning time: 0.132 ms
 Execution time: 0.047 ms
Run Code Online (Sandbox Code Playgroud)

3)成本= 0.00..16.38没有任何索引:

 Seq Scan on group_member x2  (cost=0.00..16.38 rows=3 width=32) (actual time=0.002..0.002 rows=0 loops=1)
   Filter: ((uid)::text = 'a1'::text)
 Planning time: 42.599 ms
 Execution time: 0.402 ms
Run Code Online (Sandbox Code Playgroud)

结果#3更有效吗?为什么?


编辑 在实践中,表(group,user,group_members)中将有许多行.大约> 1百万.

Gor*_*off 6

在分析查询时,小数据集的成本查询计划通常不是较大数据集上性能的可靠指南.而且,SQL更关注的是更大的数据集而不是简单的小数据集.

从磁盘读取数据通常是查询性能的驱动因素.使用索引的主要目的是减少正在读取的数据页的数量.如果表中的所有数据都适合单个数据页,那么减少页面读取次数的机会就不多了:读取一个页面需要相同的时间,无论页面有一条记录还是100条记录.(通过页面读取以找到正确的记录也会产生开销,而索引会识别页面上的特定记录.)

索引会产生开销,但通常比读取数据页要少得多.索引本身需要被读入内存 - 这意味着两个页面被读入内存而不是一个.有人可能会争辩说,对于适合一页或两页的表格,使用索引可能不是一个很大的优势.

虽然使用索引(在这种情况下)确实需要更长的时间,但在几分之一毫秒内测量的性能差异通常与大多数数据库任务没有密切关系.如果要查看索引是否正常工作,请在表中放置100,000行并运行相同的测试.你会看到没有索引的版本大致与表中的数据量成比例; 具有索引的版本相对恒定(实际上,缩放更像是表中记录数的日志).