无法优化mySQL查询

时间:2015-02-19 22:09:47

标签: mysql sql query-optimization

我正在运行查询以从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,所以请在回复时考虑这些信息,谢谢:)

4 个答案:

答案 0 :(得分:0)

它看起来不像查询有问题。

  1. 查看应用程序代码。最有可能的问题出在代码
  2. 检查MySQL query execution plan
    • 可能你错过了索引
  3. 确保在Application和Database中缓存数据(fyi,有时您可以将整个数据库加载到应用程序内存中)
  4. 确保使用连接池
  5. 创建视图(改进的机会非常小)
  6. 尝试删除" Order By"条款(再次提高性能的可能性很小)

答案 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