Mysql 相对简单的查询速度非常慢。我做错了什么?
只涉及4个表,所以我不知道为什么在我的数据库上执行这项操作需要90多秒 records表中大约有300万条记录,但是软件中没有其他查询像这个查询那么慢。有许多复杂得多的查询比这个查询快得多,所以我知道我做错了什么 这确实产生了正确的结果,但速度太慢了。。我做错了什么 选择 r、 id为'id`, concatr.fname,,r.lname作为“申请人”, r、 添加了“应用程序时间”, concatrimr.city,,r.state为'city`, coalesceq.count,0表示“尝试”, coalesceq.last_调用,0作为“last called”, null作为“已删除”` 来自myfreshp_crm记录r 左连接 选择rid,countrid作为count,maxcalled作为上次调用 从myfreshp_crm.cc_队列 其中status='called' 按rid分组 q上的q.rid=r.id 左连接 选择rid,maxtime作为应用程序 从myfreshp_crm.calendar 其中event='约会' 按rid分组 a.rid上的a=r.id 左连接 选择rid,maxsent as sent 从myfreshp_crm.cc_队列 按rid分组 c.rid上的c=r.id 哪里 r、 id不在从asap_黑名单中选择lead_id中 和聚结Q.计数,0<4 和 c、 已发送>UNIX_时间戳-60*60*24*28或 r、 添加>UNIX_时间戳-60*60*24*28 和 a、 appt不为空 和a.apptMysql 相对简单的查询速度非常慢。我做错了什么?,mysql,sql,performance,subquery,left-join,Mysql,Sql,Performance,Subquery,Left Join,只涉及4个表,所以我不知道为什么在我的数据库上执行这项操作需要90多秒 records表中大约有300万条记录,但是软件中没有其他查询像这个查询那么慢。有许多复杂得多的查询比这个查询快得多,所以我知道我做错了什么 这确实产生了正确的结果,但速度太慢了。。我做错了什么 选择 r、 id为'id`, concatr.fname,,r.lname作为“申请人”, r、 添加了“应用程序时间”, concatrimr.city,,r.state为'city`, coalesceq.count,0表示“尝
+----+-------------+----------------+------+---------------+-------------+---------+-------------------+---------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------------+------+---------------+-------------+---------+-------------------+---------+----------+----------------------------------------------+
| 1 | PRIMARY | r | ALL | added,source | NULL | NULL | NULL | 3436521 | 100.00 | Using where |
| 1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 4 | myfreshp_crm.r.id | 10 | 100.00 | Using where |
| 1 | PRIMARY | <derived3> | ref | <auto_key1> | <auto_key1> | 4 | myfreshp_crm.r.id | 15 | 100.00 | Using where |
| 1 | PRIMARY | <derived4> | ref | <auto_key1> | <auto_key1> | 4 | myfreshp_crm.r.id | 15 | 100.00 | Using where |
| 5 | SUBQUERY | asap_blacklist | ALL | NULL | NULL | NULL | NULL | 287 | 100.00 | NULL |
| 4 | DERIVED | cc_queue | ALL | rid | NULL | NULL | NULL | 77090 | 100.00 | Using temporary; Using filesort |
| 3 | DERIVED | calendar | ALL | rid,event | NULL | NULL | NULL | 102750 | 97.15 | Using where; Using temporary; Using filesort |
| 2 | DERIVED | cc_queue | ALL | rid,status | NULL | NULL | NULL | 77090 | 99.39 | Using where; Using temporary; Using filesort |
+----+-------------+----------------+------+---------------+-------------+---------+-------------------+---------+----------+----------------------------------------------+
8 rows in set, 1 warning (0.08 sec)
记录表:
创建表“记录”
`id`int20非空自动增量,
`uid`int20不为空,
`cid`int20不为空,
`vid`int8不为空,
`添加了'int25 NOT NULL,
`fname`varchar50不为空,
`mname`varchar50不为空,
`lname`varchar50不为空,
`地址'varchar200不为空,
`城市'varchar50不为空,
`状态“varchar50”不为空,
`zip`int5不为空,
`phone1`varchar16不为空,
`phone2`varchar16不为空,
`mobilephone`varchar16不为空,
`电子邮件'varchar100不为空,
`状态'enum'active'、'inactive'、'followup'、'responsed'、'sell'、'dead'不为空,
`ssn`varchar11不为空,
`perm`enum'yes','no'不为空默认值'no',
`打印标签'int30不为空,
`打印字母'int30不为空,
`dob`varchar20不为空,
`源'varchar15非空默认值'imported',
`选择退出'enum'no','yes'不为空默认值'no',
`其他_数据`长文本不为空,
`“int11”中的sms_opt_不为空,
主键'id`,
键'cid``cid`,
键'uid``uid`,
键'vid``vid`,
键'status`` status`,
键'uid_2``uid`,
键'printed_label`` printed_label`,
键'fname``fname`,
键'mname``mname`,
键'lname``lname`,
键'phone1``phone1`,
键'phone2``phone2`,
输入'printed\u letter`` printed\u letter`,
关键字“地址”``地址`,
关键城市城市,
键'state``state`,
键'added`` added`,
键`source``source`,
键'email``email`,
键'zip``zip`,
键'ssn``ssn`,
键'dob``dob`
ENGINE=InnoDB AUTO_INCREMENT=8938455默认字符集=1
cc_队列表:
创建表“cc_队列”
`id`int20非空自动增量,
`rid`int20不为空,
`已发送'int30非空,
`称为'int30 NOT NULL,
`原因'varchar150 COLLATE utf8\u unicode\u ci非空,
`状态'enum'waiting','called'COLLATE utf8\u unicode\u ci NOT NULL,
`处置`长文本整理utf8\u unicode\u ci不为空,
`注释'varchar250 COLLATE utf8\u unicode\u ci NOT NULL,
`sentToCC`int11不为空,
主键'id`,
键'rid``rid`,
键'status`` status`,
键`sent``sent`,
键`called`` called`,
键'sentToCC``sentToCC`
ENGINE=MyISAM自动增量=77097默认字符集=utf8 COLLATE=utf8\U unicode\U ci
日历表:
创建“日历”表
`id`int11非空自动增量,
`uid`int11不为空,
`rid`int20不为空,
`添加了'int25 NOT NULL,
`时间'int11不为空,
`事件'varchar500 COLLATE utf8\u unicode\u ci NOT NULL,
`详细信息'varchar1000 COLLATE utf8\u unicode\u ci NOT NULL,
主键'id`,
键'uid``uid`,
键'rid``rid`,
键'added`` added`,
键'time``time`,
键'event``事件'333
ENGINE=MyISAM自动增量=151930默认字符集=utf8 COLLATE=utf8\U unicode\U ci
asap_黑名单表:
创建表'asap_blacklist`
`id`int11非空自动增量,
`时间'int11不为空,
`lead_id`int11不为空,
主键'id`
ENGINE=InnoDB自动增量=1483默认字符集=utf8 COLLATE=utf8\U bin
下面是信息模式所说的
加入
子查询确实会对性能产生负面影响。
在可能的情况下,我将使用视图的连接替换这些连接
我发现,甚至像你在WHERE子句中的那句话。。。
r、 id不在从asap_黑名单中选择lead_id中
替换为以下内容时,速度会快得多:
左尽快加入BL.Lead\U ID=R.ID上的黑名单BL
和
BL.Lead_ID为空连接到子查询确实会对性能产生不利影响。 在可能的情况下,我将使用视图的连接替换这些连接 我发现,甚至像你在WHERE子句中的那句话。。。 r、 id不在从asap_黑名单中选择lead_id中 替换为以下内容时,速度会快得多: 左尽快加入BL.Lead\U ID=R.ID上的黑名单BL 和
BL.Lead_ID为空您可以简化代码 首先,您在myfreshp_crm.cc_队列中聚合两次,并将两个结果集分别加入myfreshp_crm.records,但您可以使用条件聚合进行一次聚合。 q和c别名子查询可以合并为以下内容:
SELECT rid,
COUNT(CASE WHENE status = 'called' THEN rid END) AS count,
MAX(CASE WHENE status = 'called' THEN called END) AS last_called,
MAX(sent) AS sent
FROM myfreshp_crm.cc_queue
GROUP BY rid
还要简化WHERE子句中的条件
条件:
a.appt is not null and a.appt < UNIX_TIMESTAMP()
c.sent is not null and c.sent > a.appt
可以简化为:
c.sent > a.appt
因此,请尝试以下代码:
SELECT r.id AS `ID`,
CONCAT(r.fname, ' ', r.lname) AS `Applicant`,
r.added `App Time`,
CONCAT(trim(r.city), ', ', r.state) AS `City`,
COALESCE(q.count, 0) AS `Attempts`,
COALESCE(q.last_called, 0) AS `Last Called`,
NULL AS `Removed`
FROM myfreshp_crm.records r
LEFT join (
SELECT rid,
COUNT(CASE WHENE status = 'called' THEN rid END) AS count,
MAX(CASE WHENE status = 'called' THEN called END) AS last_called,
MAX(sent) AS sent
FROM myfreshp_crm.cc_queue
GROUP BY rid
) q ON q.rid = r.id
LEFT join (
SELECT rid, MAX(time) AS appt
FROM myfreshp_crm.calendar
WHERE event = 'Appointment'
GROUP BY rid
) a ON a.rid = r.id
WHERE r.id NOT IN (SELECT lead_id FROM asap_blacklist)
AND COALESCE(q.count, 0) < 4
AND (q.sent > (UNIX_TIMESTAMP() - (60 * 60 * 24 * 28)) OR r.added > (UNIX_TIMESTAMP() - (60 * 60 * 24 * 28)))
AND ((a.appt < UNIX_TIMESTAMP() AND q.sent > a.appt) OR (r.source = 'Online' AND a.appt is NULL))
您可以简化代码 首先,您在myfreshp_crm.cc_队列中聚合两次,并将两个结果集分别加入myfreshp_crm.records,但您可以使用条件聚合进行一次聚合。 q和c别名子查询可以合并为以下内容:
SELECT rid,
COUNT(CASE WHENE status = 'called' THEN rid END) AS count,
MAX(CASE WHENE status = 'called' THEN called END) AS last_called,
MAX(sent) AS sent
FROM myfreshp_crm.cc_queue
GROUP BY rid
还要简化WHERE子句中的条件
条件:
a.appt is not null and a.appt < UNIX_TIMESTAMP()
c.sent is not null and c.sent > a.appt
可以简化为:
c.sent > a.appt
因此,请尝试以下代码:
SELECT r.id AS `ID`,
CONCAT(r.fname, ' ', r.lname) AS `Applicant`,
r.added `App Time`,
CONCAT(trim(r.city), ', ', r.state) AS `City`,
COALESCE(q.count, 0) AS `Attempts`,
COALESCE(q.last_called, 0) AS `Last Called`,
NULL AS `Removed`
FROM myfreshp_crm.records r
LEFT join (
SELECT rid,
COUNT(CASE WHENE status = 'called' THEN rid END) AS count,
MAX(CASE WHENE status = 'called' THEN called END) AS last_called,
MAX(sent) AS sent
FROM myfreshp_crm.cc_queue
GROUP BY rid
) q ON q.rid = r.id
LEFT join (
SELECT rid, MAX(time) AS appt
FROM myfreshp_crm.calendar
WHERE event = 'Appointment'
GROUP BY rid
) a ON a.rid = r.id
WHERE r.id NOT IN (SELECT lead_id FROM asap_blacklist)
AND COALESCE(q.count, 0) < 4
AND (q.sent > (UNIX_TIMESTAMP() - (60 * 60 * 24 * 28)) OR r.added > (UNIX_TIMESTAMP() - (60 * 60 * 24 * 28)))
AND ((a.appt < UNIX_TIMESTAMP() AND q.sent > a.appt) OR (r.source = 'Online' AND a.appt is NULL))
并去掉status、rid和event上相应的单列
从
AND r.id not in (select lead_id from asap_blacklist)
到
并去掉status、rid和event上相应的单列
从
AND r.id not in (select lead_id from asap_blacklist)
到
它可能是缺少的索引,请共享explain extended的结果我添加了output@eshirvana。它可能是缺少的索引,请共享explain extended的结果我添加了output@eshirvana.VIEWs是语法糖;它们不提供任何性能提升—甚至不提供物化视图?MySQL有这些吗?MySQL没有物化视图。除非你自己做,比如使用Trigger.Hmmm,从很久以前开始,我认为他们教我优化/编译视图,使它们比直接解释的SQL更快;它们不提供任何性能提升—甚至不提供物化视图?MySQL有这些吗?MySQL没有物化视图。除非你自己做,比如使用Trigger.Hmmm,从很久以前开始,我认为他们教我优化/编译视图,使它们比解释的直接SQL更快。这个答案加上@RickJames答案的后半部分将执行时间减少了近50%。等到我有更多的时间尝试使用索引,然后再选择对性能影响最大的答案。这个答案与@RickJames答案的后半部分结合起来,将执行时间减少了近50%。在选择对性能影响最大的答案之前,等待我有更多的时间尝试使用索引。