1

如何优化其 WHERE 条件包括检查 user_id = X OR user_id IN 的查询(一些可能不返回结果的子查询)

在下面的示例中,查询 1 和 2 都非常快(< 1 毫秒),但查询 3(只是查询 1 和 2 中条件的 OR)要慢得多(50 毫秒)

有人可以解释一下为什么查询 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

在这个特定查询中,大部分时间都与索引扫描有关。这是一个从不同角度进行的查询,以避免这种情况,但应该返回等效的结果。

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

这从用户表中选择,执行一次过滤器,然后将帖子加入到该表中。

我意识到这个问题是关于优化技巧的,而不是这个特定的查询。为了回答这个问题,我的建议是运行EXPLAIN ANALYZE并阅读解释结果, -这个答案对我有帮助。

于 2012-12-17T20:38:40.323 回答
0

How about:

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 回答