我有一张桌子朋友:
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
如何优化此查询的索引?
谢谢。
答案 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
,你会发现双引号的标准含义是用于分隔表名和列名字,而不是字符串。