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

标签 mysql left-join

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

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

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

这样做的目的是从状态为 != 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))

解释输出:

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

最佳答案

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

如果有一些更好的条件,比如 jobs.status = 331 和 ack = 0(请注意,我已经将 != 更改为 = ) 那么建议加快这个查询:

  1. 将查询拆分为 2,由 UNION ALL 连接
  2. 将一个查询中的 LEFT JOIN 替换为 INNER JOIN(在暗示 wq.info 不为 NULL 的查询中)

关于mysql - 尝试使用 LEFT OUTER JOIN 优化 MySQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5442420/

相关文章:

java - 申请者无法建立连接。 (打开的文件太多)

php - Laravel 迁移 : auto increment key when it is not primary

mysql - 如何使我的数据库连接正常工作?

mysql - 将列中的值映射到 SQL 中的值

php - 选择t2中不存在的行,基于t1 mysql

mysql - 如何找到使用 Mysql 函数的位置?

mysql - 使用选择联合构建 MySQL View

MySQL - 基于同一表中的行求和列值

php - LEFT JOIN 快捷方式在使用 OOP 和 PDO 时导致错误

mysql - CakePHP 3 : How to automatically get fields from leftJoin?