2016-08-02 12 views
0

**** **** EDIT'IN'クエリを最適化するにはどうすればよいですか?

14msは多くのことを思えないかもしれない、しかし、あなたは「PostgresSQLの説明」には以下を参照することができますよう、PostgreSQLの80,000行に配列スキャンを行っています。このスキャンを避け、いくつかのインデックス検索を行う方法がなければなりません。

**** EDITのEND ****

私は、スキーマレスなアイデアで遊んでいると私は、次の3つのテーブルを持っている:

テーブル10万件のランダムエントリが移入されています。 index_username_email(key)

上の非ユニークインデックスを持つ

entities(_primary_key SERIAL PRIMARY KEY, _id CHAR(32) UNIQUE, 
    data BYTEA) 

index_username_profile_names(_id CHARE(32) PRIMARY KEY, 
    key VARCHAR UNIQUE) 

index_username_email(_id CHAR(32) PRIMARY KEY, key VARCHAR) 

私のSQLクエリは次のとおりです。

SELECT data FROM entities WHERE 
    _id IN (SELECT _id FROM index_users_email WHERE key = 'test') 
OR 
    _id in (SELECT _id FROM index_users_profile_name WHERE key = 'test') 

「テストは」「インデックスのどちらかではない終了をするが、これは百日咳約14msを消費しとります私がPostgreSQLかMySQLを使用していても、それは私が間違っているものでなければなりません。

どのように私はそれを最適化することができますか、または何を間違っているのですか?

ありがとうございます!

Postgresは説明:1つの潜在的な答えはunionjoinあるよう

Seq Scan on entities (cost=16.88..4776.15 rows=80414 width=163) (actual time=15.169..15.169 rows=0 loops=1) 
    Filter: ((hashed SubPlan 1) OR (hashed SubPlan 2)) 
    Rows Removed by Filter: 107218 
    SubPlan 1 
    -> Index Scan using index_users_email_key_idx1 on index_users_email (cost=0.42..8.44 rows=1 width=33) (actual time=0.039..0.039 rows=0 loops=1) 
      Index Cond: ((key)::text = 'test'::text) 
    SubPlan 2 
    -> Index Scan using index_users_profile_name_key_idx1 on index_users_profile_name (cost=0.42..8.44 rows=1 width=33) (actual time=0.071..0.071 rows=0 loops=1) 
      Index Cond: ((key)::text = 'test'::text) 
Planning time: 0.202 ms 
Execution time: 15.216 ms 
+4

14 *ミリ秒* "なんと" ではありません。 –

+0

1ms未満でなければなりません:D –

+0

それ以下はありません8 ms – Drew

答えて

1

OR編(join-は)条件は、通常は悪いです、代わりにUNIONを試してみてください。

SELECT data FROM entities 
WHERE _id IN 
(SELECT _id 
    FROM index_users_email 
    WHERE key = 'test' 
) 
UNION 
SELECT data FROM entities 
WHERE _id in 
(SELECT _id 
    FROM index_users_profile_name 
    WHERE key = 'test' 
) 
+0

Yeap。 UNIONはそれをしました。私は "IN"をJOINに変更し、それは魅力のように機能します。 –

+0

もう一度ありがとうございます:D –

0
SELECT data 
FROM entities e 
    LEFT OUTER JOIN index_users_email iue ON e._id=iue._id and iue.key = 'test' 
    LEFT OUTER JOIN index_users_profile_name iupn ON e._id=iupn._id and iupn .key = 'test' 
WHERE 
    iue._id IS NOT NULL or iupn._id IS NOT NULL 
+0

このトリックをしていないようです。 40ms –

+0

このコードは問題を解決するのに役立つかもしれませんが、 _why_および/または_how_に関する追加のコンテキストを提供すると、 の質問はその長期的価値を大幅に改善します。 の制限事項と前提条件を含む説明を追加するには、回答を編集してください。 –

0

が見える:

explain select data from entities as t join (select _id from index_users_email where key = 'test' union select _id from index_users_profile_name where key = 'test') u on t._id = u._id; 
                   QUERY PLAN                 
------------------------------------------------------------------------------------------------------------------------------------------- 
Nested Loop (cost=17.32..33.82 rows=2 width=163) 
    -> Unique (cost=16.90..16.91 rows=2 width=33) 
     -> Sort (cost=16.90..16.91 rows=2 width=33) 
       Sort Key: index_users_email._id 
       -> Append (cost=0.42..16.89 rows=2 width=33) 
        -> Index Scan using index_users_email_key_idx1 on index_users_email (cost=0.42..8.44 rows=1 width=33) 
          Index Cond: ((key)::text = 'test'::text) 
        -> Index Scan using index_users_profile_name_key_idx1 on index_users_profile_name (cost=0.42..8.44 rows=1 width=33) 
          Index Cond: ((key)::text = 'test'::text) 
    -> Index Scan using entities__id_key on entities t (cost=0.42..8.44 rows=1 width=196) 
     Index Cond: (_id = index_users_email._id) 
(11 rows) 

Time: 0.714 ms 
+1

'explain 'の代わりに' explain analyze'を使用してください。 – joop

0

それはそれらのテーブルの主キーを利用していますので、これは良いパフォーマンスを持っています:

select data 
from entities 
where 
    exists (
     select _id 
     from index_users_email 
     where key = 'test' and _id = entities._id 
    ) or exists (
     select _id 
     from index_users_profile_name 
     where key = 'test' and _id = entities._id 
    ) 
+0

それは16msかかります。それはあなたが言及したようにすべてのキーを使用しますが、最終的にエンティティのseq scan ... "エンティティのSeqスキャン(コスト= 0.00..95578​​2.93行= 80414幅= 163)(実際の時間= 15.524..15.524行= 0ループ= 1) " –

1

14ミリ秒はかなり上手です。なぜクエリがミリ秒未満で実行されるべきなのか考えていません。クエリを設定し、データがメモリ上にあることを検証し、インデックスがどこにあるかなどを特定する作業が「たくさん」あります。私はそれを引用符で囲みます。なぜなら、ほとんどのクエリでは、これは簡単なことです。しかし、それは簡単にミリ秒に追加することができます。

第二に、あなたは次の点に注意してください、実際のタイミングを行っている場合:

  • コンピュータ(私たちはそれらを使用するように)決定論的ではありません。タイミングを複数回実行する必要があります。ミリ秒かかる何かのために、これは安定した読書を得るために通常何千回もあります。
  • タイミングごとにシステムを同じ状態に初期化します。コールド・キャッシュまたはウォーム・キャッシュを使用するかどうかを決定する必要がありますが、タイミングはすべて同じシステム上にある必要があります。
  • システムを他の作業と分離します。バックグラウンドタスク(マウスの移動を含む)は、パフォーマンスに影響する可能性があります。クエリの面では

は、私は考えることができる一つのことは=existsを使用することです:

SELECT e.data 
FROM entities e 
WHERE _id = (SELECT _id FROM index_users_email WHERE key = 'test') OR 
     EXISTS (SELECT 1 FROM index_users_profile_name iupn WHERE iupn._id = e.id AND iupn.key = 'test'); 

せいぜい、しかし、私はオフミリ秒か2を剃るでしょうこれらを推測していますクエリ。

+0

Postgres Explainをご覧ください。 Seq Scanの理由はありません。また、0.5msかかるクエリーの14msは大きな低下です。 –

+0

関連する統計のseqscan:abscenseには適切な理由があります。 – wildplasser

関連する問題