尝试使用LEFT OUTER JOIN优化MySQL查询

时间:2011-03-26 12:54:09

标签: mysql left-join

我有这个查询,除了需要很长时间(7秒,在jobs表中有40k记录,在wq表中有700k)时工作正常。

我尝试了一个EXPLAIN,它说它查看作业表中的所有记录,而不是使用任何索引。

我不知道如何告诉MySQL它应该使用jobs.status字段在查找wq表之前过滤记录。

这样做的目的是获取状态为!= 331的作业的所有记录,以及具有wq状态(101,111,151)的任何其他作业。

查询:

SELECT jobs.*
FROM jobs
LEFT OUTER JOIN wq ON (wq.job = jobs.id AND jobs.status IN (341, 331) AND wq.status IN (101, 111, 151))
WHERE ((wq.info is not NULL) or (jobs.status != 331 and ack = 0))

EXPLAIN输出:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  jobs    ALL     ack,status,status_ack   NULL    NULL    NULL    38111   Using filesort
1   SIMPLE  wq  ref     PRIMARY,job,status  PRIMARY     4   cts.jobs.id     20  Using where

表定义:

CREATE TABLE jobs ( id int(10) NOT NULL AUTO_INCREMENT,
comment varchar(100) NOT NULL DEFAULT '',
profile varchar(60) NOT NULL DEFAULT '',
start_at int(10) NOT NULL DEFAULT '0',
data text NOT NULL,
status int(10) NOT NULL DEFAULT '0',
info varchar(200) NOT NULL DEFAULT '',
finish int(10) NOT NULL DEFAULT '0',
priority int(5) NOT NULL DEFAULT '0',
ack tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (id),
KEY start_at (start_at),
KEY status (status),
KEY status_ack (status,
ack) ) ENGINE=MyISAM AUTO_INCREMENT=2037530 DEFAULT CHARSET=latin1;


CREATE TABLE wq ( job int(10) NOT NULL DEFAULT '0',
process varchar(60) NOT NULL DEFAULT '',
step varchar(60) NOT NULL DEFAULT '',
status int(10) NOT NULL DEFAULT '0',
run_at int(10) NOT NULL DEFAULT '0',
original_run_at int(10) NOT NULL DEFAULT '0',
info varchar(200) NOT NULL DEFAULT '',
pos int(10) NOT NULL DEFAULT '0',
changed_at int(10) NOT NULL DEFAULT '0',
file varchar(60) NOT NULL DEFAULT '',
PRIMARY KEY (job,
process,
step,
file),
KEY job (job),
KEY status (status) ) ENGINE=MyISAM DEFAULT CHARSET=latin1

1 个答案:

答案 0 :(得分:5)

不幸的是,mysql(也许还有任何dbms)无法优化像jobs.status != 331 and ack = 0这样的表达式,因为B-Tree不是一种允许快速找到任何不等于常数值的结构的结构。因此,您将始终获得全扫描。

如果有更好的条件,例如jobs.status = 331 and ack = 0(请注意我已将!=更改为=),那么建议加快此查询:< / p>

  1. 将查询拆分为2,由UNION ALL
  2. 加入
  3. 在一个查询中LEFT JOIN替换为INNER JOIN(在暗示wq.info is not NULL的那个中)