在用数据填充表之前或在数据到位之后创建索引是否更好?

Dre*_*ens 73 mysql database indexing

我有一个大约100M行的表,我将要复制以更改,添加索引.我不是很关心创建新表所花费的时间,但是如果我在插入任何数据之前更改表或首先插入数据然后添加索引,那么创建的索引会更有效吗?

val*_*zka 95

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

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
Run Code Online (Sandbox Code Playgroud)

插入然后创建索引 - 大约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
Run Code Online (Sandbox Code Playgroud)

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

  • +1,索引将显着减慢涉及100M行插入任务的操作,因此最好删除它们并重新创建它们. (5认同)
  • 10K 行怎么样?100行?是否存在先创建索引速度更快的截止点?插入和索引的数据又如何(文本、地理、整数)?这会改变这一切吗? (2认同)

Mar*_*ins 8

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

编辑 "平衡"可能不是这里的最佳术语选择.在b树的情况下,它根据定义进行平衡.但这并不意味着b树具有最佳布局.父节点内的子节点分布可能不均匀(导致未来更新中的成本增加),如果在更新期间未仔细执行平衡,则树深度可能会超过必要的深度.如果在添加行之后创建索引,则更有可能具有更好的分布.此外,构建索引后,磁盘上的索引页可能具有较少的碎片. 这里有更多信息


Svi*_*ack 7

这对于这个问题并不重要,因为:

  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))额外的时间。