随着我的私人消息数据库开始增长,我注意到以下查询的一些相当缓慢的下降。
查询:
SELECT * FROM privatemessages WHERE sender='940' OR recipient='940' ORDER BY id DESC LIMIT 1000;
(940可以是任何用户ID)
表:
CREATE TABLE `privatemessages` (
`id` int(11) NOT NULL auto_increment,
`recipient` int(11) NOT NULL,
`sender` int(11) NOT NULL,
`time` int(11) NOT NULL,
`readstatus` int(11) NOT NULL,
`message` varchar(255) NOT NULL,
`messagetype` int(11) NOT NULL,
`rdeleted` int(11) NOT NULL,
`sdeleted` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `recipient` (`recipient`),
KEY `sender` (`sender`),
KEY `read` (`readstatus`),
KEY `time` (`time`),
KEY `openmessagingpanel` (`recipient`,`readstatus`),
KEY `openpmthreadrev` (`recipient`,`sender`),
KEY `openpmthread` (`sender`,`recipient`)
) ENGINE=InnoDB AUTO_INCREMENT=8650153 DEFAULT CHARSET=latin1
MySQL解释:
+----+-------------+-----------------+-------------+------------------------------------------------------------------+------------------+---------+------+-------+--------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------------+------------------------------------------------------------------+------------------+---------+------+-------+--------------------------------------------+
| 1 | SIMPLE | privatemessages | index_merge | recipient,sender,openmessagingpanel,openpmthreadrev,openpmthread | sender,recipient | 4,4 | NULL | 26100 | Using union(sender,recipient); Using where |
+----+-------------+-----------------+-------------+------------------------------------------------------------------+------------------+---------+------+-------+--------------------------------------------+
1 row in set (0.00 sec)
有谁知道我需要做些什么才能让这个查询恢复速度?大约有800万条记录。
谢谢。
答案 0 :(得分:1)
不幸的是,其中包含 OR 的查询很慢,因为它们无法充分利用索引。但是,有一个解决方案。可以向数据库表达更便宜但功能相同的请求。您可以 optimize query performance by replacing the ORs with UNION-ed queries 代替,所有 UNION ed 查询都可以最佳索引。
您需要按如下方式转换您的查询。它适用于 CTE,但如果您使用的 MySQL 版本没有可用的 CTE,您可以轻松地使用子查询或临时表重写它。
WITH
cts AS
(
SELECT *
FROM privatemessages
WHERE sender='940'
ORDER BY id DESC
LIMIT 1000
),
ctr AS
(
SELECT *
FROM privatemessages
WHERE recipient='940'
ORDER BY id DESC
LIMIT 1000
)
SELECT * FROM cts
UNION
SELECT * FROM ctr
ORDER BY id desc
LIMIT 1000;
这些 CTE 子查询中的每一个都会以最佳索引方式运行,并在找到前 1000 行后停止。然后将两者结合起来,并根据 id 排序丢弃一半的结果。获取 2,000 行以返回 1,000 行仍然比您的 EXPLAIN 显示(扫描 26,100 行)快 13 倍。
答案 1 :(得分:0)
2个想法:
答案 2 :(得分:0)
您已经在发件人和收件人列上有一个索引。
假设您需要GUI的请求,用户可以选择要阅读的消息:
如果你只选择id,title和时间,这足以显示消息的链接。你可以将限制设置为50左右并进行一些分页。
或者您是否需要它进行某种出口?那么你应该使用mysql的导出功能......
希望这会对你有所帮助。