优化我桌上的索引

时间:2013-11-11 16:25:34

标签: mysql sql optimization

我有一张桌子朋友

CREATE TABLE IF NOT EXISTS `friends` (
    `fr_id` int(11) NOT NULL AUTO_INCREMENT,
    `fr_sender` int(11) NOT NULL,
    `fr_receiver` int(11) NOT NULL,
    `fr_validate` enum('0','1','2') NOT NULL DEFAULT '0',
    PRIMARY KEY (`fr_id`),
    KEY `fr_sender` (`fr_sender`),
    KEY `fr_receiver` (`fr_receiver`),
    KEY `fr_validate` (`fr_validate`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2397953 ;

fr_id       => index
fr_sender   => sender of the friend request
fr_receiver => the receiver
fr_falidate => 0 = no reply, 1 = request accepted, 2 = request refused.

我的mysql-slow.log有很多行用于此查询:

SELECT fr_id FROM friends WHERE (fr_sender = '113405' OR fr_receiver = '113405') && fr_validate = "1";
# Query_time: 5.607869  Lock_time: 0.000052 Rows_sent: 106  Rows_examined: 833517

如何优化此查询的索引?

谢谢。

1 个答案:

答案 0 :(得分:1)

在两个不同列的条件之间使用OR时,优化很棘手。它经常导致昂贵的表扫描。

这是一种解决方法:

ALTER TABLE friends 
 ADD INDEX (fr_validate, fr_sender),
 ADD INDEX (fr_validate, fr_receiver);

SELECT fr_id FROM friends WHERE fr_validate = '1' AND fr_sender = '113405'
UNION 
SELECT fr_id FROM friends WHERE fr_validate = '1' AND fr_receiver = '113405'

创建两个索引的原因是每个子查询都有一个相应的索引,以尽可能减少检查的行数。然后将每个子查询的结果组合在一起,得到与原始查询相同的结果集。

PS:请使用单引号作为字符串文字和日期文字。 MySQL允许双引号默认提供相同的角色,但是如果你使用另一个RDBMS品牌,或者如果你在MySQL中使用SET SQL_MODE=ANSI_QUOTES,你会发现双引号的标准含义是用于分隔表名和列名字,而不是字符串。