2

希望对使用索引(或者实际上是查询本身)优化 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

查询显然有效,而且做得还不错,但我们最近确实增加了流量,现在我可以看到它开始挣扎了。

干杯!

4

2 回答 2

2

优化查询时要记住的一件事是 MySQL在执行查询时只会选择一个索引;盲目地索引您能想到的任何字段组合可能无济于事,实际上会减慢插入速度。

这看起来像一个典型的桌子,有两个玩家组成一个团队,所以因为你不确定被查询的用户是否会在user1或者user2你搜索两者。这很可能导致所有键都被拒绝并因此执行表扫描。

我的建议是稍微非规范化您的表并创建一个单独的表,您可以在其中存储(user_id, partnership_id)并加上一个跨越主键,其中的每条记录partnerships是该表中的两条记录;这消除了OR,您可以使用一个简单JOIN的从更大的表中获取您需要的信息。

为了帮助您调查这些问题,您可以使用EXPLAIN <query>查看 MySQL 如何“攻击”您的查询。

于 2012-12-20T10:51:37.177 回答
0

你真的需要一切吗?

SELECT *

为 WHERE 子句创建索引

INDEX(user1_id, user1_strike, user2_id, user2_strike)

您还可以在索引中包含 timestemp 并将排序设置为 ASC。

除此之外,数据库的表可能需要额外的索引并且可能需要重新设计。还要考虑检查 SQL 服务器设置(使用 InnoDB 表,并为服务器设置正确的缓存/内存限制)。

于 2012-12-20T10:37:08.620 回答