類似性関数の最適なインデックス


8

したがって、このテーブルには620万件のレコードが含まれており、列の類似性を使用して検索クエリを実行する必要があります。クエリは次のとおりです。

 SELECT  "lca_test".* FROM "lca_test"
 WHERE (similarity(job_title, 'sales executive') > 0.6)
 AND worksite_city = 'los angeles' 
 ORDER BY salary ASC LIMIT 50 OFFSET 0

where(year = X、worksite_state = N、status = 'certified'、visa_class = Z)にさらに条件を追加できます。

これらのクエリの一部を実行すると、30秒を超える非常に長い時間がかかる場合があります。時々1分以上。

EXPLAIN ANALYZE 前述のクエリの私にこれを与えます:

Limit  (cost=0.43..42523.04 rows=50 width=254) (actual time=9070.268..33487.734 rows=2 loops=1)
->  Index Scan using index_lca_test_on_salary on lca_test  (cost=0.43..23922368.16 rows=28129 width=254) (actual time=9070.265..33487.727 rows=2 loops=1)
>>>> Filter: (((worksite_city)::text = 'los angeles'::text) AND (similarity((job_title)::text, 'sales executive'::text) > 0.6::double precision))
>>>> Rows Removed by Filter: 6330130 Total runtime: 33487.802 ms
Total runtime: 33487.802 ms

列を高速にインデックス化する方法を理解できません。

編集:これはpostgresバージョンです:

x86_64-unknown-linux-gnu上のPostgreSQL 9.3.5、gcc(Debian 4.7.2-5)4.7.2、64ビットでコンパイル

これがテーブル定義です:

                                                         Table "public.lca_test"
         Column         |       Type        |                       Modifiers                       | Storage  | Stats target | Description
------------------------+-------------------+-------------------------------------------------------+----------+--------------+-------------
 id                     | integer           | not null default nextval('lca_test_id_seq'::regclass) | plain    |              |
 raw_id                 | integer           |                                                       | plain    |              |
 year                   | integer           |                                                       | plain    |              |
 company_id             | integer           |                                                       | plain    |              |
 visa_class             | character varying |                                                       | extended |              |
 employement_start_date | character varying |                                                       | extended |              |
 employement_end_date   | character varying |                                                       | extended |              |
 employer_name          | character varying |                                                       | extended |              |
 employer_address1      | character varying |                                                       | extended |              |
 employer_address2      | character varying |                                                       | extended |              |
 employer_city          | character varying |                                                       | extended |              |
 employer_state         | character varying |                                                       | extended |              |
 employer_postal_code   | character varying |                                                       | extended |              |
 employer_phone         | character varying |                                                       | extended |              |
 employer_phone_ext     | character varying |                                                       | extended |              |
 job_title              | character varying |                                                       | extended |              |
 soc_code               | character varying |                                                       | extended |              |
 naic_code              | character varying |                                                       | extended |              |
 prevailing_wage        | character varying |                                                       | extended |              |
 pw_unit_of_pay         | character varying |                                                       | extended |              |
 wage_unit_of_pay       | character varying |                                                       | extended |              |
 worksite_city          | character varying |                                                       | extended |              |
 worksite_state         | character varying |                                                       | extended |              |
 worksite_postal_code   | character varying |                                                       | extended |              |
 total_workers          | integer           |                                                       | plain    |              |
 case_status            | character varying |                                                       | extended |              |
 case_no                | character varying |                                                       | extended |              |
 salary                 | real              |                                                       | plain    |              |
 salary_max             | real              |                                                       | plain    |              |
 prevailing_wage_second | real              |                                                       | plain    |              |
 lawyer_id              | integer           |                                                       | plain    |              |
 citizenship            | character varying |                                                       | extended |              |
 class_of_admission     | character varying |                                                       | extended |              |
Indexes:
    "lca_test_pkey" PRIMARY KEY, btree (id)
    "index_lca_test_on_id_and_salary" btree (id, salary)
    "index_lca_test_on_id_and_salary_and_year" btree (id, salary, year)
    "index_lca_test_on_id_and_salary_and_year_and_wage_unit_of_pay" btree (id, salary, year, wage_unit_of_pay)
    "index_lca_test_on_id_and_visa_class" btree (id, visa_class)
    "index_lca_test_on_id_and_worksite_state" btree (id, worksite_state)
    "index_lca_test_on_lawyer_id" btree (lawyer_id)
    "index_lca_test_on_lawyer_id_and_company_id" btree (lawyer_id, company_id)
    "index_lca_test_on_raw_id_and_visa_and_pw_second" btree (raw_id, visa_class, prevailing_wage_second)
    "index_lca_test_on_raw_id_and_visa_class" btree (raw_id, visa_class)
    "index_lca_test_on_salary" btree (salary)
    "index_lca_test_on_visa_class" btree (visa_class)
    "index_lca_test_on_wage_unit_of_pay" btree (wage_unit_of_pay)
    "index_lca_test_on_worksite_state" btree (worksite_state)
    "index_lca_test_on_year_and_company_id" btree (year, company_id)
    "index_lca_test_on_year_and_company_id_and_case_status" btree (year, company_id, case_status)
    "index_lcas_job_title_trigram" gin (job_title gin_trgm_ops)
    "lca_test_company_id" btree (company_id)
    "lca_test_employer_name" btree (employer_name)
    "lca_test_id" btree (id)
    "lca_test_on_year_and_companyid_and_wage_unit_and_salary" btree (year, company_id, wage_unit_of_pay, salary)
Foreign-key constraints:
    "fk_rails_8a90090fe0" FOREIGN KEY (lawyer_id) REFERENCES lawyers(id)
Has OIDs: no

少なくともテーブル定義(正確なデータ型と制約を含む)とPostgresのバージョンを含めることは明らかです。tag-infoのpostgresql-performanceへの指示を検討してください。また、に常に等価条件があるかどうかを明確にしworksite_cityます。
Erwin Brandstetter 2015年

おかげで、私はそれらの情報/を含むように私の投稿を編集しました。そして、はい、常に上の等価条件があり worksite_cityworksite_stateyearおよび/または status
BL0B

回答:


14

機能pg_trgmを提供する追加モジュールをインストールしたことを忘れていましたsimilarity()

類似演算子 %

まず、他に何をする場合でも%、式の代わりに類似性演算子を使用します(similarity(job_title, 'sales executive') > 0.6)。もっと安い。また、インデックスのサポートは関数ではなく、Postgresの演算子にバインドされています。

の望ましい最小類似度を取得するには、次のコマンドを0.6実行します。

SELECT set_limit(0.6);

別の設定にリセットしない限り、設定はセッションの残りの部分に残ります。確認する:

SELECT show_limit();

これは少し不格好ですが、パフォーマンスには最適です。

シンプルなケース

job_title文字列「sales Executive」の列で最も一致するものが必要な場合、これは「最も近い隣人」検索の単純なケースであり、トライグラム演算子クラスを使用してGiSTインデックスで解決できますgist_trgm_ops(ただしGINインデックスでは解決できません)。 :

CREATE INDEX trgm_idx ON lcas USING gist (job_title gist_trgm_ops);

等価条件も含めるにはworksite_city、追加のモジュールが必要になりますbtree_gist。実行(DBごとに1回):

CREATE EXTENSION btree_gist;

次に:

CREATE INDEX lcas_trgm_gist_idx ON lcas USING gist (worksite_city, job_title gist_trgm_ops);

クエリ:

SELECT set_limit(0.6);  -- once per session

SELECT *
FROM   lca_test
WHERE  job_title % 'sales executive'
AND    worksite_city = 'los angeles' 
ORDER  BY (job_title <-> 'sales executive')
LIMIT  50;

<-> 「距離」演算子であること:

1マイナスsimilarity()値。

Postgresは、二つの別々のインデックス、上の無地のbtreeインデックス組み合わせることができworksite_city、そして上の別々のGiSTインデックスをjob_titleを組み合わせることができますが、クエリでこのように2つのカラムを定期的に組み合わせる場合、複数カラムインデックスが最も高速になります。

あなたの場合

ただし、クエリはsalary距離/類似性ではなくで並べ替えられるため、ゲームの性質が完全に変わります。これでGINとGiSTの両方のインデックスを使用できるようになり、GINはより高速になります(GINインデックスが大幅に改善されたPostgres 9.4ではさらにヒント-ヒント!)

追加の同等性チェックについても同様のストーリーworksite_city:追加のモジュールをインストールしますbtree_gin。実行(DBごとに1回):

CREATE EXTENSION btree_gin;

次に:

CREATE INDEX lcas_trgm_gin_idx ON lcas USING gin (worksite_city, job_title gin_trgm_ops);

クエリ:

SELECT set_limit(0.6);  -- once per session

SELECT *
FROM   lca_test
WHERE  job_title % 'sales executive'
AND    worksite_city = 'los angeles' 
ORDER  BY salary 
LIMIT  50 -- OFFSET 0

繰り返しますが、これはすでに持っているより単純なインデックスでも(あまり効率的ではなく)機能するはずです("index_lcas_job_title_trigram")と(おそらく他のインデックスと組み合わせて)機能し。最善の解決策は全体像に依存します。

アサイド

  • インデックスがたくさんあります。それらがすべて使用されていて、維持費を支払っていますか?

  • 疑わしいデータタイプがいくつかあります。

    employement_start_date | character varying
    employement_end_date   | character varying

    それらがあるべきであるように思えますdate。等。

関連する回答:


私は持っていない"index_lcas_job_title_trigram" gin (job_title gin_trgm_ops)私はジンが速く要旨よりであることをどこかで読みました。本当?
bl0b 2015年

1
@ bl0b、ginはまったくサポートsimilarityしていません。そのため、そのための速度は速くありません。
jjanes

@ bl0b:jjanesは正しい(そしてそれも私の最初のアイデアでした)が、あなたのケースは異なり、結局GINインデックスを使用できます。もっとたくさん追加しました。
Erwin Brandstetter 2015年

@ErwinBrandstetter回答ありがとうございます!簡単な質問:あなたは、GINの方が高速で、インストールする必要があると言っていbtree_ginます。しかし、次に、インデックス作成で実行するように指示します。CREATE INDEX lcas_trgm_gin_idx ON lcas USING gist (worksite_city, job_title gist_trgm_ops);タイプミスだけですか?
bl0b 2015年

1
@ErwinBrandstetter 30秒から6秒に行った。素晴らしい改善!どうもありがとう!
bl0b 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.