使用OR运算符时,MySQL Query速度变慢

时间:2011-04-26 07:32:48

标签: mysql mysql-management

随着我的私人消息数据库开始增长,我注意到以下查询的一些相当缓慢的下降。

查询:

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万条记录。

谢谢。

3 个答案:

答案 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个想法:

  • 是否值得为状态未删除的消息创建一个视图,并从那里选择消息,假设将有更少的recs来处理。
  • 关于选择所需字段的冗长通常会产生性能提升

答案 2 :(得分:0)

您已经在发件人和收件人列上有一个索引。

假设您需要GUI的请求,用户可以选择要阅读的消息:

如果你只选择id,title和时间,这足以显示消息的链接。你可以将限制设置为50左右并进行一些分页。

或者您是否需要它进行某种出口?那么你应该使用mysql的导出功能......

希望这会对你有所帮助。