1

WHERE条件にuser_id=Xまたはuser_idIN(結果を返さない可能性のあるサブクエリ)のチェックが含まれるクエリを最適化するにはどうすればよいですか?

以下の私の例では、クエリ1と2はどちらも非常に高速(<1 ms)ですが、クエリ3はクエリ1と2の条件の単なるORであり、はるかに低速です(50 ms)

誰かがクエリ3が非常に遅い理由を説明できますか?また、一般に、この問題を回避するためにどのタイプのクエリ最適化戦略を追求する必要がありますか?私の例のサブクエリは簡単に削除できることを理解していますが、実際には、サブクエリが必要なデータを取得するための最も簡単な方法のように見えることがあります。

関連するコードとデータ:

投稿データ https://dl.dropbox.com/u/4597000/StackOverflow/sanitized_posts.csv

ユーザーデータ https://dl.dropbox.com/u/4597000/StackOverflow/sanitized_users.csv

# from the shell:
# > createdb test

CREATE TABLE posts (
  id integer PRIMARY KEY NOT NULL,
  created_by_id integer NOT NULL,
  created_at integer NOT NULL
);
CREATE INDEX index_posts ON posts (created_by_id, created_at);
CREATE INDEX index_posts_2 ON posts (created_at);

CREATE TABLE users (
  id integer PRIMARY KEY NOT NULL,
  login varchar(50) NOT NULL
);
CREATE INDEX index_users ON users (login);

COPY posts FROM '/path/to/sanitized_posts.csv' DELIMITERS ',' CSV;
COPY users FROM '/path/to/sanitized_users.csv' DELIMITERS ',' CSV;


-- queries:

-- query 1, fast:
EXPLAIN ANALYZE SELECT * FROM posts WHERE created_by_id = 123 LIMIT 100;

-- query 2, fast:
EXPLAIN ANALYZE SELECT * FROM posts WHERE created_by_id IN (SELECT id FROM users WHERE login = 'nobodyhasthislogin') LIMIT 100;

-- query 3, slow:
EXPLAIN ANALYZE SELECT * FROM posts WHERE created_by_id = 123 OR created_by_id IN (SELECT id FROM users WHERE login = 'nobodyhasthislogin') LIMIT 100;
4

3 に答える 3

1

クエリを分割します (編集済み):

SELECT * FROM (
    SELECT * FROM posts p WHERE p.created_by_id = 123 
    union    
    SELECT * FROM posts p
    WHERE 
      EXISTS ( SELECT TRUE FROM users WHERE id = p.created_by_id AND login = 'nobodyhasthislogin')
  ) p
  LIMIT 100;
于 2012-12-17T20:14:32.573 に答える
0

どうですか:

EXPLAIN ANALYZE
SELECT  * 
FROM    posts
WHERE   created_by_id IN (
           SELECT 123
           UNION ALL
           SELECT id FROM
           users  WHERE
           login  = 'nobodyhasthislogin') LIMIT 100;
于 2012-12-17T22:54:47.397 に答える
0

この特定のクエリのほとんどの時間は、インデックス スキャンに関連しています。これを回避するために別の角度からクエリを実行しますが、同等の結果を返す必要があります。

SELECT posts.* FROM users JOIN posts on posts.created_by_id=users.id WHERE users.id=123 or login='nobodyhasthislogin'

これは users テーブルから選択し、フィルターを 1 回実行してから、投稿をそれに結合します。

質問は最適化のヒントに関するものであり、実際にはこの特定のクエリではないことに気付きました。それに答えるために、私の提案はEXPLAIN ANALYZE、結果の解釈について実行して読むことです-この答えは私にとって役に立ちました.

于 2012-12-17T20:38:40.323 に答える