23

600万レコードのテーブルがあるとしましょう。16個の整数列といくつかのテキスト列があります。これは読み取り専用のテーブルであるため、すべての整数列にインデックスがあります。すべてのレコードは約50〜60バイトです。

テーブル名は「アイテム」
です。サーバーは、12 GB RAM、1.5 TB SATA、4コアです。postgres用のすべてのサーバー。
このデータベースにはさらに多くのテーブルがあるため、RAMがすべてのデータベースをカバーするわけではありません。

テーブル「Item」に列「a_elements」(大きな整数の配列型)を追加したいすべてのレコードは、この列に50〜60個以下の要素を持ちます。

その後、この列にインデックスGINを作成すると、一般的なクエリは次のようになります。

select * from item where ...... and '{5}' <@ a_elements;

私には、2番目のより古典的なオプションもあります。

列a_elementsをテーブルアイテムに追加せずに、2つの列を持つテーブル要素を作成します。

  • id_item
  • id_element

このテーブルには約200百万のレコードがあります。

このテーブルでパーティション分割を行うことができるので、レコード数はテーブル要素で20百万、テーブルアイテムで500Kに減少します。

2番目のオプションクエリは次のようになります。

select item.* 
from item 
    left join elements on (item.id_item=elements.id_item) 
where .... 
and 5 = elements.id_element

パフォーマンスの観点から、どのオプションが優れているのだろうか。postgresは、単一のクエリでインデックスGIN(オプション1)を使用して多くの異なるインデックスを使用できますか?

このデータのインポートには20日かかるため、適切な決定を下す必要があります。

4

1 に答える 1

18

私はあなたがelementsテーブルを使うべきだと思います:

  • Postgresは統計を使用して、クエリを実行する前に一致する行数を予測できるため、最適なクエリプランを使用できます(データが均等に分散されていない場合はより重要です)。

  • CLUSTER elements USING elements_id_element_idx;を使用してクエリデータをローカライズできます。

  • Postgres 9.2がリリースされると、インデックスのみのスキャンを利用できるようになります。

しかし、私は10Mの要素に対していくつかのテストを行いました。

create table elements (id_item bigint, id_element bigint);
insert into elements
  select (random()*524288)::int, (random()*32768)::int
    from generate_series(1,10000000);

\timing
create index elements_id_item on elements(id_item);
Time: 15470,685 ms
create index elements_id_element on elements(id_element);
Time: 15121,090 ms

select relation, pg_size_pretty(pg_relation_size(relation))
  from (
    select unnest(array['elements','elements_id_item', 'elements_id_element'])
      as relation
  ) as _;
      relation       | pg_size_pretty 
---------------------+----------------
 elements            | 422 MB
 elements_id_item    | 214 MB
 elements_id_element | 214 MB



create table arrays (id_item bigint, a_elements bigint[]);
insert into arrays select array_agg(id_element) from elements group by id_item;

create index arrays_a_elements_idx on arrays using gin (a_elements);
Time: 22102,700 ms

select relation, pg_size_pretty(pg_relation_size(relation))
  from (
    select unnest(array['arrays','arrays_a_elements_idx']) as relation
  ) as _;
       relation        | pg_size_pretty 
-----------------------+----------------
 arrays                | 108 MB
 arrays_a_elements_idx | 73 MB

そのため、一方で配列は小さく、インデックスも小さくなります。決定を下す前に、2億個の要素テストを行います。

于 2012-08-03T11:46:49.960 に答える