我有一个大约100M行的表,我将要复制以进行更改,添加索引。我不是很关心创建新表所花费的时间,但是如果我在插入任何数据之前更改表或首先插入数据然后添加索引,那么创建的索引会更有效吗?
答案 0 :(得分:87)
在数据插入后创建索引是一种更有效的方法(甚至经常建议在批量导入之前和导入之后删除索引)。
Syntetic示例(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秒(慢两倍以上)
答案 1 :(得分:8)
在添加行之后创建索引可能更好。它不仅会更快,而且树平衡可能会更好。
编辑“平衡”可能不是这里的最佳选择。在b树的情况下,它根据定义进行平衡。但这并不意味着b树具有最佳布局。父节点内的子节点分布可能不均匀(导致未来更新中的成本增加),如果在更新期间未仔细执行平衡,则树深度可能会超过必要的深度。如果在添加行之后创建索引,则更有可能具有更好的分布。此外,构建索引后,磁盘上的索引页可能具有较少的碎片。 A bit more information here
答案 2 :(得分:2)
这与此问题无关,因为:
O(n*log(N))
更长(其中n
是添加的行)。由于树格协作时间为O(N*log(N))
,因此如果您将其分为旧数据和新数据,则可以O((X+n)*log(N))
将其转换为O(X*log(N) + n*log(N))
,并且可以使用此格式简单地查看您的内容等一下。n
个新行)你得到更长的时间插入额外的时间O(log(N))
来重新生成树的结构后添加新元素(新行的索引列,因为索引已存在和新添加了行,然后必须将索引重新生成为平衡结构,此成本O(log(P))
其中P
是索引幂 [索引中的元素] )。您有n
个新行,最后您有n * O(log(N))
,然后O(n*log(N))
汇总其他时间。答案 3 :(得分:1)
在大多数情况下,之后创建的索引要快得多。例证:varchar上有2000万行全文(255) - (商家名称) 导入行时的索引 - 在最坏的情况下匹配最多需要20秒。 丢弃索引并重新创建 - 每次匹配不到1秒
答案 4 :(得分:-1)
我不确定索引效率是否真的很重要,因为在这两种情况下,您都会在索引中插入新数据。基本上,服务器在构建之前不会知道索引的不平衡程度。显然,速度明智地是没有索引的插入。