web-dev-qa-db-ja.com

テーブルにデータを入力する前に、またはデータが配置された後に、インデックスを作成する方が良いでしょうか?

約1億行のテーブルがあり、これをコピーして変更し、インデックスを追加します。新しいテーブルの作成にかかる時間はあまり気にしませんが、データを挿入する前にテーブルを変更するか、最初にデータを挿入してからインデックスを追加すると、作成されたインデックスはより効率的になりますか?

72
Drew Stephens

データの挿入後にインデックスを作成する方がより効率的な方法です(バッチインポート前およびインポート後にインデックスを再作成することをお勧めします)。

合成例(PostgreSQL 9.1、遅い開発マシン、100万行):

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秒(2倍以上遅い)

91
valodzka

行を追加した後にインデックスを作成する方がおそらく良いでしょう。より速くなるだけでなく、ツリーのバランスがおそらく良くなります。

Edit「バランシング」は、おそらくここでの用語の最良の選択ではありません。 Bツリーの場合、定義によってバランスが取られます。しかし、それはBツリーが最適なレイアウトを持っていることを意味しません。親内での子ノードの分布は不均一である可能性があり(将来の更新でコストが高くなる)、更新中にバランスを慎重に実行しないと、ツリーの深さが必要以上に深くなる可能性があります。行が追加された後にインデックスが作成される場合、より良い分布を持つ可能性が高くなります。さらに、ディスク上のインデックスページは、インデックスの作成後に断片化が少なくなる場合があります。 ここでもう少し情報

8
Mark Wilkins

これはこの問題では重要ではありません:

  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))の要約追加時間があります。
2
Svisstack

後に作成されるインデックスは、ほとんどの場合非常に高速です。適切なケース:varchar(255)に全文を含む2000万行-(ビジネス名)行のインポート中にインデックスを配置-最悪の場合で最大20秒かかることとの一致。インデックスを削除して再作成する-毎回1秒未満で取得する

1
Mike Cross