我正在运行查询以从MySQL数据库中检索一些游戏关卡。查询本身大约需要0.00025秒才能在包含40个级别字符串的基础上执行。我认为这是令人满意的,直到我收到网站主持人的消息告诉我优化下面提到的查询,否则脚本将被删除,因为它会给他们的服务器带来很大压力。
我尝试使用explain进行优化并解释扩展和相应调整列(添加索引),但总是得到相同的性能。我还注意到,MySQL并没有使用可用的索引,而是进行了全表扫描。
EXPLAIN EXTENDED的结果:
table id select_type type possible_keys key key_len ref rows Extra
users 1 SIMPLE ALL PRIMARY,id NULL NULL NULL 7 Using temporary; Using filesort
AllTime 1 SIMPLE ref PRIMARY,userid PRIMARY 4 Test.users.id 1
查询:
SELECT users.nickname, AllTime.userid, AllTime.id, AllTime.levelname, AllTime.levelstr
FROM AllTime
INNER JOIN users
ON AllTime.userid=users.id
ORDER BY AllTime.id DESC
LIMIT ($value_from_php),20;
表格: 用户
| id(int) | nickname(varchar) |
| (Primary, Auto_increment) | |
|---------------------------|-------------------|
| 1 | username1 |
| 2 | username2 |
| 3 | username3 |
| ... | ... |
和AllTime
| id(int) | userid(int) | levelname(varchar) | levelstr(text) |
| (Primary, Auto_increment) | (index) | | |
|---------------------------|-------------|--------------------|----------------|
| 1 | 2 | levelname1 | levelstr1 |
| 2 | 2 | levelname2 | levelstr2 |
| 3 | 3 | levelname3 | levelstr3 |
| 4 | 1 | levelname4 | levelstr4 |
| 5 | 1 | levelname5 | levelstr5 |
| 6 | 1 | levelname6 | levelstr6 |
| 7 | 2 | levelname7 | levelstr7 |
有没有办法优化这个查询,或者我最好通过从php调用两个连续查询来避免警告?
我只是在学习MySQL,所以请在回复时考虑这些信息,谢谢:)
答案 0 :(得分:0)
它看起来不像查询有问题。
答案 1 :(得分:0)
查询本身需要 0.00025秒 ...我收到了来自网站主机的消息,告诉我要优化下面提到的查询,否则脚本将被删除,因为它正在推动他们的服务器上有很多压力。
向网站主机询问有关此查询被标记为何会引起注意的详细信息。除非被频繁调用,否则一个微不足道的查询不会对任何事情造成压力。
找出该查询运行的次数。我敢打赌你的网站正在被机器人敲打并且每分钟被执行数百或数千次。如果是这样,那那就是你真正的问题。
答案 2 :(得分:0)
我假设你正在使用InnoDB。
对于INNER JOIN,MySQL通常从包含最少行的表开始,在本例中为users
。但是,由于您只希望最新的20 AllTime
条记录与相应的user
记录相关联,因此实际应该从AllTime
开始,因为LIMIT
,它会更小数据集。
使用STRAIGHT_JOIN强制加入顺序:
SELECT users.nickname, AllTime.userid, AllTime.id, AllTime.levelname,
AllTime.levelstr
FROM AllTime
STRAIGHT_JOIN users
ON users.id = AllTime.userid
ORDER BY AllTime.id DESC
LIMIT ($value_from_php),20;
它应该能够使用AllTime
表上的主键并按降序排列。它会抓取同一页面上的所有数据。
它还应该使用users表上的主键来获取id和昵称。如果只有两列,则可以在(id,nickname)上添加多列覆盖索引以提高速度。
如果可以,请将levelstr
列转换为VARCHAR
,以便将数据存储在与其余数据相同的页面上,否则,必须单独获取文本列。这假设您的列在InnoDB的8000字节行限制之下。除非您删除文本列,否则无法避免USING TEMPORARY
。
最有可能的是,您的主机已使用慢查询日志识别此查询,该日志可识别所有不使用索引的查询,或者由于Using temporary
而可能已将其标记为红色。
答案 3 :(得分:0)
LIMIT ($value_from_php),20;
- 如果$ value_form_php很大,那么查询速度很慢。这是因为在到达您需要的20之前,需要扫描所有“旧”页面。
通过“记住你离开的地方”,你可以使每个页面同样快速。有关详细信息,请参阅此处:http://mysql.rjweb.org/doc.php/pagination