非常喜欢使用索引(或者实际上是查询本身)优化MySQL查询。
表格结构:
CREATE TABLE IF NOT EXISTS `match_current` (
`partnership_id` int(11) NOT NULL AUTO_INCREMENT,
`runs` int(5) NOT NULL DEFAULT '0',
`balls` int(5) NOT NULL DEFAULT '0',
`user1_id` bigint(11) NOT NULL,
`user1_firstname` char(20) NOT NULL,
`user1_lastname` char(20) NOT NULL,
`user1_runs` int(5) NOT NULL DEFAULT '0',
`user1_balls` int(5) NOT NULL DEFAULT '0',
`user1_strike` tinyint(1) NOT NULL DEFAULT '1',
`user1_out` tinyint(1) NOT NULL DEFAULT '0',
`user1_retired` tinyint(1) NOT NULL DEFAULT '0',
`user2_id` bigint(11) NOT NULL,
`user2_firstname` char(20) NOT NULL,
`user2_lastname` char(20) NOT NULL,
`user2_runs` int(5) NOT NULL DEFAULT '0',
`user2_balls` int(5) NOT NULL DEFAULT '0',
`user2_strike` tinyint(1) NOT NULL DEFAULT '0',
`user2_out` tinyint(1) NOT NULL DEFAULT '0',
`user2_retired` tinyint(1) NOT NULL DEFAULT '0',
`last_over` char(15) NOT NULL,
`ball_by_ball` varchar(1000) NOT NULL,
`facebook` tinyint(1) NOT NULL DEFAULT '0',
`friends` tinyint(1) NOT NULL DEFAULT '0',
`nudge` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`started` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`status` tinyint(1) NOT NULL DEFAULT '1',
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`partnership_id`),
UNIQUE KEY `user1_id_2` (`user1_id`,`user2_id`,`facebook`),
KEY `user2_id` (`user2_id`),
KEY `user1_id` (`user1_id`),
KEY `facebook` (`facebook`),
KEY `status` (`status`),
KEY `friends` (`friends`),
KEY `timestamp` (`timestamp`),
KEY `user1_id_3` (`user1_id`,`user1_strike`),
KEY `user2_id_2` (`user2_id`,`user2_strike`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=36139 ;
示例查询:
SELECT *
FROM match
WHERE status = 1
AND (
(user1_id=1234 AND user1_strike=1) OR
(user2_id=4321 AND user2_strike=1)
)
ORDER BY timestamp ASC
查询显然有效并且没有做得太糟糕但我们最近确实增加了流量,现在我可以看到它开始挣扎。
干杯!
答案 0 :(得分:2)
优化查询时要记住的一件事是MySQL在执行查询时只会选择一个索引;盲目索引你能想到的任何字段组合可能没什么用,实际上减慢了插入速度。
这看起来像一个典型的桌子,有两个玩家组成一个团队,所以因为你不确定被查询的用户是在user1
还是user2
,你搜索两者。这很可能导致所有密钥被拒绝,并因此执行表扫描。
我的建议是稍微反规范化你的表并创建一个单独的表,你存储(user_id, partnership_id)
和一个生成主键,partnerships
中的每个记录都是这个表中的两个记录;这消除了OR
,您可以使用简单的JOIN
从更大的表中获取所需的信息。
为了帮助您调查这些问题,您可以使用EXPLAIN <query>
查看MySQL如何“攻击”您的查询。
答案 1 :(得分:0)
你真的需要一切吗?
SELECT *
为WHERE子句
创建索引INDEX(user1_id, user1_strike, user2_id, user2_strike)
您还可以包含时间段并在索引中将排序设置为ASC。
除了这些之外,数据库的表可能需要额外的索引并且可能需要重新设计。还要考虑检查SQL服务器设置(使用InnoDB表,并为服务器设置正确的缓存/内存限制)。