在用数据填充表之前或在数据放置后创建索引更好吗?


87

我有一张大约1亿行的表,要复制更改以添加索引。我不是很在意创建新表的时间,但是如果在插入任何数据之前先更改表或先插入数据然后再添加索引,创建的索引会更有效吗?

Answers:


113

在数据插入之后创建索引是更有效的方法(甚至经常建议在批量导入之前和导入之后重新创建索引以删除索引)。

语法示例(PostgreSQL 9.1,缓慢的开发机,一百万行):

CREATE TABLE test1(id serial, x integer);
INSERT INTO test1(id, x) SELECT x.id, x.id*100 FROM generate_series(1,1000000) AS x(id);
-- Time: 7816.561 ms
CREATE INDEX test1_x ON test1 (x);
-- Time: 4183.614 ms

插入然后创建索引-大约12秒

CREATE TABLE test2(id serial, x integer);
CREATE INDEX test2_x ON test2 (x);
-- Time: 2.315 ms
INSERT INTO test2(id, x) SELECT x.id, x.id*100 FROM generate_series(1,1000000) AS x(id);
-- Time: 25399.460 ms

创建索引,然后插入-大约25.5秒(慢两倍以上)


5
+1,索引会明显减慢涉及100M行插入任务的操作,因此最好删除它们并重新创建它们。
code4life

10

添加行后创建索引可能更好。它不仅会更快,而且树平衡可能会更好。

编辑“平衡”可能不是此处术语的最佳选择。对于b树,其定义是平衡的。但这并不意味着b树具有最佳布局。如果更新期间未仔细执行平衡,则父节点中子节点的分布可能会不均匀(导致将来的更新成本增加),并且树的深度最终可能会变得比所需的更深。如果在添加行之后创建索引,则索引更有可能具有更好的分布。此外,在建立索引之后,磁盘上的索引页可能碎片较少。 这里有更多信息


2

这个问题无关紧要,因为:

  1. 如果首先将数据添加到表中,然后在其后添加索引。您的索引生成时间将O(n*log(N))更长(在其中n添加行)。因为树发芽时间O(N*log(N))到了,如果您将其分为旧数据和新数据,O((X+n)*log(N))则可以将其简单地转换为原始数据,O(X*log(N) + n*log(N))并以这种格式,可以简单地看到还要等待的时间。
  2. 如果添加索引并在其后放置数据。每行(有n新行)都O(log(N))需要更长的时间,将新元素添加到树中后,需要额外的时间来重新生成树的结构(新行的索引列,因为索引已经存在并且已经添加了新行,则必须重新生成索引才能平衡结构,这种成本O(log(P))其中P是一个指数功率[在索引元件])。你有n新行那么最后你有n * O(log(N))那么O(n*log(N))总结更多的时间。

1

在大多数情况下,之后创建的索引要快得多。恰当的例子:2,000万行带有varchar(255)上的全文-在导入行的同时具有(公司名称)索引-在最坏的情况下,最多需要20秒才能匹配。删除索引并重新创建-匹配每次花费少于1秒的时间


-2

我不确定对于索引效率而言是否真的很重要,因为在两种情况下,您都将新数据插入索引中。基本上直到索引建立之后,服务器才会知道索引的不平衡程度。速度明智,显然,在没有索引的情况下进行插入。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.