web-dev-qa-db-ja.com

Postgresテーブルのインデックスをできるだけ速く作成する

インデックスのないPostgresテーブルに大きなデータベースインポート(100GB)があります。

インポート後、クエリのインデックスをできるだけ早く作成したいと考えています。インデックスの準備ができていない限り、テーブル内のデータにはアクセスされません。

インデックスを作成する最も速い方法は何ですか? 3つの列(2つのvarchar、1つのdate)でインデックスを構築する必要があります。インデックスの作成には約2時間かかりますが、これは実際には役に立ちません。

インデックスの作成を高速化できる方法はありますか?おそらく、データのインポート前にインデックスを設定する方が良いでしょう。これにより、インポートが遅くなりますか?

Postgresには「ロックせずに」インデックスを作成するオプションがあることは承知していますが、インデックスが作成されている間にPostgresがデータにアクセスできるため、減少パフォーマンスではないでしょうか?

これは仮想マシンです。サーバーのメモリを必要に応じて増やすことができます。現在32GBあります。 work_memおよびmaintenance_work_memはデフォルトの設定値のままです。データベース用のSSDがありません。これは確かにスピードアップしますか?

部分インデックスに使用できるbooleanフラグなどはありません。実際、テーブルの各行にインデックスを付ける必要があります。

5
membersound

オプションの場合、データベースをインポートする前に、データを外部で事前に並べ替えることができます。

PostgreSQL 9.6.1を使用したテストでは、3つの倍精度列とランダム値を持つ10Mレコードを含むテーブルにより、同じデータでインデックスを作成しましたが、事前に順序付けされているため、インデックス作成時間の70%が削減されました。

db=# create table indexing_test_data (a varchar(50), b varchar(50), c real);       
CREATE TABLE
Time: 3,586 ms
db=# insert into indexing_test_data select random()::text, random()::text, random() from generate_series(1, 10000000);
INSERT 0 10000000
Time: 25590,475 ms
db=# select a, b, c into indexing_test_sorted from indexing_test_data order by a, b, c;
SELECT 10000000
Time: 77389,665 ms

db=# create index test_data_idx on indexing_test_data (a, b, c);
CREATE INDEX
Time: 57399,140 ms

db=# create index test_sorted_idx on indexing_test_sorted (a, b, c);
CREATE INDEX
Time: 16219,639 ms

Cのロケールと照合を備えたデータベースを使用する余裕がある場合は、さらに高速化できます。これにより、PostgreSQL 9.5以降で使用できる短縮キーと呼ばれる機能を使用できます。 これはソートを最大20倍高速化しますが、Cロケールでのみ機能します 、古いライブラリでのバグのあるロケールサポートのため:

db=# create database testdb lc_collate "C" lc_ctype "C" template template0;
CREATE DATABASE
Time: 429,710 ms
db=# \c testdb
You are now connected to database "testdb" as user "user".
testdb=# create table indexing_test_data (a varchar(50), b varchar(50), c real);       
CREATE TABLE
Time: 2,794 ms
testdb=# insert into indexing_test_data select random()::text, random()::text, random() from generate_series(1, 10000000);
INSERT 0 10000000
Time: 25977,964 ms
testdb=# select a, b, c into indexing_test_sorted from indexing_test_data order by a, b, c;
SELECT 10000000
Time: 20794,850 ms

testdb=# create index test_data_idx on indexing_test_data (a, b, c);
CREATE INDEX
Time: 16371,426 ms

testdb=# create index test_sorted_idx on indexing_test_sorted (a, b, c);
CREATE INDEX
Time: 8046,787 ms

ここでは、並べ替えられたデータのインデックス作成には、並べ替えられていない場合の約50%の時間がかかりますが、57秒かかった最初のバージョンと比較すると、ダウンしています時間の14%まで

コメントで述べたように、他のことも役立ちます:maintenance_work_memを適切に設定し、create index concurrentlyを実行しない(これはかなり低速です)。

5
hruske