我正在制作PHP
后端API,该API在MySQL
数据库上执行查询。这是查询:
SELECT * FROM $TABLE_GAMES WHERE
($GAME_RECEIVERID = '$userId'OR $GAME_OTHERID = '$userId')
ORDER BY $GAME_ID LIMIT 1"
本质上,我将$userId
作为参数传递,并获得具有最小$GAME_ID
值的行,对于表中具有约30 000个匹配行的用户,它将在不到100毫秒的时间内返回结果。但是,此后,我添加了新用户,这些用户具有<100个匹配的行,查询对于他们来说非常缓慢,每次大约需要20-30秒。
我很困惑,为什么在应该返回少量行的情况下查询如此慢,而在返回大量行的情况下却变得如此快,特别是因为我有ORDER BY
。
我已经阅读了有关参数嗅探的信息,但据我所知,这是SQL
服务器的事,我正在使用MySQL
。
编辑
这里是SHOW CREATE
语句:
[CREATE TABLE
games(
IDint(11) NOT NULL AUTO_INCREMENT,
SenderIDint(11) NOT NULL,
ReceiverIDint(11) NOT NULL,
OtherIDint(11) NOT NULL,
Timestamptimestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (
ID )
) ENGINE=MyISAM AUTO_INCREMENT=17275279 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
这里是EXPLAIN
的输出
+----+-------------+-------+------+---------------+------+---------+-----+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
+----+-------------+-------+------+---------------+------+---------+-----+------+-------+
| 1 | SIMPLE | games | NULL | index | NULL | PRIMARY | 4 | NULL | 1 |
+----+-------------+-------+------+---------------+------+---------+-----+------+-------+
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE games NULL index NULL PRIMARY 4 NULL 1 19.00 Using where
我尝试了准备好的语句,但仍然得到相同的结果。
对不起,格式化不好,我仍然对此不满意。
EXPLAIN SELECT * FROM $TABLE_GAMES WHERE
($GAME_RECEIVERID = '$userId'OR $GAME_OTHERID = '$userId')
ORDER BY $GAME_ID LIMIT 1"
EXPLAIN
将提供有关带有执行计划的选择查询的信息。这是识别查询速度缓慢的好工具。根据获得的信息,您可以为Indexes
子句中使用的列创建WHERE
。
CREATE INDEX index_name ON table_name (column_list)
这肯定会提高查询的性能。
$GAME_RECEIVERID
和$GAME_OTHERID
不是索引的一部分时,就会出现该行为,由于顺序,促使MySQL使用$GAME_ID
上的索引。但是,由于较新的玩家没有玩过早期的游戏,因此实际上有数百万行不匹配,但是仍然必须进行检查。不幸的是,随着数据库的增长,即使对于老用户,这也将变得更加糟糕。理想情况下,您将在$GAME_RECEIVERID
和$GAME_OTHERID
上添加索引-类似于:
ALTER TABLE games
ADD INDEX receiver (ReceiverID),
ADD INDEX other (OtherID)
PS:更改1700万行的表将花费一些时间,因此请确保在维护时段或在生产中使用的类似时段执行此操作。