[英]Can this query be any faster?
I have got the following query: 我有以下查询:
SELECT SQL_CALC_FOUND_ROWS *
FROM (
SELECT *
FROM
(
SELECT M.id, M.project_id, M.reply_toaddress as reply_toemailaddress, M.phone_no, M.subject,M.message, M.timestamp_received, M.done, M.postpone, "mail" AS type, M.firstname, M.prefix, M.surname
FROM messages M
LEFT JOIN link_projects_mailboxes LPMB
ON M.mailbox_id = LPMB.mailbox_id
WHERE M.main_message_id =0
AND LPMB.projects_id = 13 AND ( 0 OR (M.done = 0 AND M.postpone = 0 )) AND M.status = 0
GROUP BY M.id
) M
UNION
(
SELECT C.id, C.project_id, C.reply_toemailaddress, C.phone_no, C.subject,C.message, C.timestamp_received, done, postpone, "call" AS type , C.firstname, C.prefix, C.surname
FROM calls C
WHERE 1
AND projects_id = 13 AND ( 0 OR (C.done = 0 AND C.postpone = 0 )) AND C.status = 0
)
) x ORDER BY `timestamp_received` asc LIMIT 30
The problem is that this query is running on 700.000 rows with 19.2GB data. 问题是此查询正在700.000行上运行,其数据为19.2GB。 The query runs for about 3 minutes.
查询运行大约3分钟。
If I explain the query I recieve the following result: 如果我解释该查询,则会收到以下结果:
Do you guys have any suggestions? 你们有什么建议吗?
EDIT: Show Create table: 编辑:显示创建表:
CREATE TABLE `messages` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`mailbox_id` int(11) NOT NULL,
`submessage_of` int(11) NOT NULL,
`main_message_id` int(11) NOT NULL,
`project_id` int(11) NOT NULL COMMENT 'Takes project from afasmssql_sync DB',
`categorie_id` int(11) NOT NULL,
`call_id` int(11) NOT NULL,
`to` text NOT NULL,
`cc` text NOT NULL,
`bcc` text NOT NULL,
`message_id` varchar(255) NOT NULL,
`bytes` int(11) NOT NULL,
`from` varchar(255) NOT NULL,
`sender` varchar(255) NOT NULL,
`reply_toaddress` varchar(255) NOT NULL,
`reply_toemailaddress` varchar(255) NOT NULL,
`subject` varchar(255) NOT NULL,
`order_id` int(10) NOT NULL DEFAULT '0',
`order_location` varchar(255) NOT NULL,
`firstname` varchar(200) NOT NULL,
`prefix` varchar(50) NOT NULL,
`surname` varchar(200) NOT NULL,
`emailaddress` varchar(200) NOT NULL,
`phone_no` varchar(255) NOT NULL,
`zipcode` varchar(6) NOT NULL,
`house_no` varchar(6) NOT NULL,
`house_no_add` varchar(50) NOT NULL,
`street` varchar(200) NOT NULL,
`city` varchar(200) NOT NULL,
`country` varchar(50) NOT NULL,
`language` varchar(50) NOT NULL,
`message` longtext NOT NULL,
`message_plain` longtext NOT NULL,
`message_stripped` longtext NOT NULL,
`quality_status` tinyint(1) NOT NULL,
`quality_by` int(11) NOT NULL,
`quality_date` datetime NOT NULL,
`done` tinyint(1) NOT NULL,
`done_date` datetime NOT NULL,
`done_by` int(11) NOT NULL,
`postpone` tinyint(1) NOT NULL,
`status` int(11) NOT NULL,
`manually` tinyint(1) NOT NULL,
`timestamp_received` datetime NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `mailbox_id` (`mailbox_id`),
KEY `submessage_of` (`submessage_of`),
KEY `main_message_id` (`main_message_id`),
KEY `subject` (`subject`),
KEY `done` (`done`),
KEY `postpone` (`postpone`),
KEY `status` (`status`),
KEY `project_id` (`project_id`),
KEY `categorie_id` (`categorie_id`),
KEY `call_id` (`call_id`),
KEY `done_date` (`done_date`),
KEY `timestamp_received` (`timestamp_received`),
KEY `from` (`from`),
KEY `reply_toemailaddress` (`reply_toemailaddress`),
KEY `timestamp` (`timestamp`),
FULLTEXT KEY `message` (`message`)
) ENGINE=MyISAM AUTO_INCREMENT=685579 DEFAULT CHARSET=utf8
CREATE TABLE `link_projects_mailboxes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`projects_id` int(11) NOT NULL,
`mailbox_id` int(11) NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `projects_id` (`projects_id`,`mailbox_id`)
) ENGINE=MyISAM AUTO_INCREMENT=156 DEFAULT CHARSET=latin1
CREATE TABLE `calls` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`actionline_id` int(11) NOT NULL,
`projects_id` int(11) NOT NULL,
`project_id` int(11) NOT NULL COMMENT 'Takes project from afasmssql_sync DB',
`categorie_id` int(11) NOT NULL,
`call_direction` varchar(255) NOT NULL,
`subject` varchar(255) NOT NULL,
`order_id` int(10) NOT NULL DEFAULT '0',
`order_location` varchar(255) NOT NULL,
`firstname` varchar(200) NOT NULL,
`prefix` varchar(50) NOT NULL,
`surname` varchar(200) NOT NULL,
`reply_toemailaddress` varchar(200) NOT NULL,
`phone_no` varchar(255) NOT NULL,
`zipcode` varchar(6) NOT NULL,
`house_no` varchar(6) NOT NULL,
`house_no_add` varchar(50) NOT NULL,
`street` varchar(200) NOT NULL,
`city` varchar(200) NOT NULL,
`country` varchar(50) NOT NULL,
`language` varchar(50) NOT NULL,
`message` longtext NOT NULL,
`done` tinyint(1) NOT NULL,
`done_date` datetime NOT NULL,
`done_by` int(11) NOT NULL,
`postpone` tinyint(1) NOT NULL,
`status` int(11) NOT NULL,
`timestamp_received` datetime NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `mailbox_id` (`actionline_id`),
KEY `subject` (`subject`),
KEY `done` (`done`),
KEY `postpone` (`postpone`),
KEY `status` (`status`),
KEY `project_id` (`project_id`),
KEY `projects_id` (`projects_id`),
FULLTEXT KEY `message` (`message`)
) ENGINE=MyISAM AUTO_INCREMENT=8941 DEFAULT CHARSET=utf8
EDIT: EXPLAIN based on Strawberries answer: 编辑:基于草莓的解释答案:
So, just to make things more readable, let's start with this query, and run the EXPLAIN on that instead... 因此,为了使内容更具可读性,让我们从此查询开始,然后在该查询上运行EXPLAIN ...
SELECT SQL_CALC_FOUND_ROWS *
FROM
( SELECT M.id
, M.project_id
, M.reply_toaddress as reply_toemailaddress
, M.phone_no
, M.subject
, M.message
, M.timestamp_received
, M.done
, M.postpone
, "mail" type
, M.firstname
, M.prefix
, M.surname
FROM messages M
JOIN link_projects_mailboxes LPMB
ON LPMB.mailbox_id = M.mailbox_id
WHERE M.main_message_id = 0
AND LPMB.projects_id = 13
AND M.done = 0
AND M.postpone = 0
AND M.status = 0
UNION
SELECT C.id
, C.project_id
, C.reply_toemailaddress
, C.phone_no
, C.subject
, C.message
, C.timestamp_received
, C.done
, C.postpone
, "call" type
, C.firstname
, C.prefix
, C.surname
FROM calls C
WHERE C.projects_id = 13
AND C.done = 0
AND C.postpone = 0
AND C.status = 0
) x
ORDER
BY timestamp_received ASC
LIMIT 30;
EXPLAIN for same: 解释相同:
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
| 1 | PRIMARY | <derived2> | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 218 | Using filesort |
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
| 2 | DERIVED | LPMB | ref | projects_id | projects_id | 4 | | 1 | Using index |
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
| 2 | DERIVED | M | ref | mailbox_id, | mailbox_id | 4 | ccc.LPMB.mailbox_id | 7,735 | Using where |
| | | | | main_message_id, | | | | | |
| | | | | done, | | | | | |
| | | | | postpone, | | | | | |
| | | | | status | | | | | |
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
| 3 | UNION | C | ref | done, | done | 1 | | 4 | Using where |
| | | | | postpone, | | | | | |
| | | | | status, | | | | | |
| | | | | projects_id | | | | | |
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
|(NULL)| UNION RESULT | <union2,3> | ALL | (NULL) | (NULL) | (NULL) | (NULL) | (NULL)| |
+------+--------------+------------+------+------------------+-------------+---------+---------------------+-------+----------------+
Since the two inner SELECTs
have no common rows, change UNION
to UNION ALL
. 由于两个内部
SELECTs
没有公共行,因此将UNION
更改为UNION ALL
。 That will save a dedup pass. 这样可以节省重复的通行证。 Run each of them to see which one is slower;
运行它们中的每一个,看看哪个较慢; then we can focus on it.
然后我们可以专注于它。
These 'composite' indexes may help it run significantly faster: 这些“复合”索引可以帮助它运行得更快:
M: INDEX(mailbox_id, message_id, done, postpone, status) -- in any order
calls: INDEX(projects_id, done, postpone, status) -- in any order
If you did not need SQL_CALC_FOUND_ROWS
, this would be much faster: 如果您不需要
SQL_CALC_FOUND_ROWS
,则速度会更快:
( SELECT ... FROM M ... ORDER BY ... LIMIT 30 )
UNION ALL
( SELECT ... FROM M ... ORDER BY ... LIMIT 30 )
ORDER BY ... LIMIT 30; -- yes, repeated again
It would require suitable indexes, probably the ones suggested above, with timestamp_received
added on the end . 它将需要合适的索引,可能是上面建议的索引,并在末尾添加了
timestamp_received
。 And the virtually useless JOIN LPMB
should be replaced by AND EXISTS ( SELECT ... FROM LPMB ... )
并且实际上无用的
JOIN LPMB
应该替换为AND EXISTS ( SELECT ... FROM LPMB ... )
That UNION
+ LIMIT
trick gets more complex, but still possible, if you are paginating with OFFSET
. 如果要使用
OFFSET
分页,则UNION
+ LIMIT
技巧会变得更加复杂,但仍然可以实现。
Unrelated: 无关:
Get rid of indexes on individual flags; 摆脱各个标志的索引; they are usually useless.
他们通常是无用的。
You should move from MyISAM to InnoDB. 您应该从MyISAM迁移到InnoDB。
FULLTEXT
(slightly different) is available in later versions. FULLTEXT
(略有不同)在更高版本中可用。
@dacrovinunghi - MySQL has no "bitmap" index type. @dacrovinunghi-MySQL没有“位图”索引类型。
WHERE 1
and 0 OR
come from dynamically building the WHERE
clause, but not taking the time to keep it clean. WHERE 1
和0 OR
来自动态构建WHERE
子句,但没有花时间保持它的清洁。 I prefer to build an array of clauses to be AND'd
, then implode
them. 我更喜欢构建一个将被
AND'd
与的子句数组,然后将其内implode
。 Or, if none, avoid the WHERE
all together. 或者,如果没有,则一起避开
WHERE
。
It may be better to remove the "done" (etc) items from the table. 这可能是较好的去除“完成”(ETC)从表中的项目。 That would eliminate that part(s) of the
WHERE
and shrink the table, making it more compact and efficient. 这样可以省去
WHERE
那一部分,并缩小桌子,使其更紧凑,更高效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.