mysql - 无法优化使用 ORDER BY 子句的 MySQL 查询

标签 mysql indexing sql-order-by query-optimization

我将 Drupal 6 与 MySQL 5.0.95 版一起使用,我的一个查询显示基于最新文章日期的内容速度变慢,并且由于使用频率而完全破坏了网站性能,这让我陷入了僵局。有问题的查询如下:

     SELECT n.nid, 
            n.title, 
            ma.field_article_date_format_value, 
            ma.field_article_summary_value
       FROM node n 
 INNER JOIN content_type_article ma ON n.nid=ma.nid
 INNER JOIN term_node tn            ON n.nid=tn.nid 
      WHERE tn.tid= 153 
        AND n.status=1 
   ORDER BY ma.field_article_date_format_value DESC 
      LIMIT 0, 11;

查询的 EXPLAIN 显示以下结果:

+----+-------------+-------+--------+--------------------------+---------+---------+----------------------+-------+---------------------------------+
| id | select_type | table | type   | possible_keys            | key     | key_len | ref                  | rows  | Extra                           |
+----+-------------+-------+--------+--------------------------+---------+---------+----------------------+-------+---------------------------------+
|  1 | SIMPLE      | tn    | ref    | PRIMARY,nid              | PRIMARY | 4       | const                | 19006 | Using temporary; Using filesort |
|  1 | SIMPLE      | ma    | ref    | nid,ix_article_date      | nid     | 4       | drupal_mm_stg.tn.nid |     1 |                                 |
|  1 | SIMPLE      | n     | eq_ref | PRIMARY,node_status_type | PRIMARY | 4       | drupal_mm_stg.ma.nid |     1 | Using where                     |
+----+-------------+-------+--------+--------------------------+---------+---------+----------------------+-------+---------------------------------+

这个查询看起来相对简单直接,检索属于类别(术语)153 且状态为 1(已发布)的文章。但显然,使用临时表和使用文件排序意味着查询必然会失败,据我所知浏览它。

从 ORDER BY 子句中移除 field_article_date_format_value 解决了 Using temporary;使用 filesort 减少了查询执行时间,但这是必需的并且不能权衡取舍,不幸的是,这同样适用于网站性能。

我的预感是,大部分问题来自于将文章映射到类别的 term_node 表,它是一个多对多关系表,这意味着如果文章 X 与 5 个类别 C1....C5 相关联,它将有 5 个条目该表,该表来自开箱即用的 drupal。

处理大量的数据库内容对我来说是新事物,并且经历了一些类似的查询( When ordering by date desc, "Using temporary" slows down query , MySQL performance optimization: order by datetime field ) 我试图为 content_type_article 创建一个复合索引,其 datetime 字段在 ORDER BY 子句中与其中的另一个键 (nid) 一起使用,并尝试 FORCE INDEX。

    SELECT n.nid, n.title,
           ma.field_article_date_format_value, 
           ma.field_article_summary_value 
      FROM node n 
INNER JOIN content_type_article ma FORCE INDEX (ix_article_date) ON n.nid=ma.nid 
INNER JOIN term_node tn ON n.nid=tn.nid 
     WHERE tn.tid= 153 
       AND n.status=1 
  ORDER BY ma.field_article_date_format_value DESC 
     LIMIT 0, 11;

结果和下面的 EXPLAIN 查询似乎没有多大帮助

+----+-------------+-------+--------+--------------------------+-----------------+---------+----------------------+-------+---------------------------------+
| id | select_type | table | type   | possible_keys            | key             | key_len | ref                  | rows  | Extra                           |
+----+-------------+-------+--------+--------------------------+-----------------+---------+----------------------+-------+---------------------------------+
|  1 | SIMPLE      | tn    | ref    | PRIMARY,nid              | PRIMARY         | 4       | const                | 18748 | Using temporary; Using filesort |
|  1 | SIMPLE      | ma    | ref    | ix_article_date          | ix_article_date | 4       | drupal_mm_stg.tn.nid |     1 |                                 |
|  1 | SIMPLE      | n     | eq_ref | PRIMARY,node_status_type | PRIMARY         | 4       | drupal_mm_stg.ma.nid |     1 | Using where                     |
+----+-------------+-------+--------+--------------------------+-----------------+---------+----------------------+-------+---------------------------------+

字段n.nid, ca.nid, ma.field_article_date_format_value 都被索引了。使用 ORDER BY 子句查询 Limit 0,11 的数据库大约需要 7-10 秒,但如果没有它,查询几乎不需要一秒钟。数据库引擎是MyISAM。对此的任何帮助将不胜感激。

任何可以帮助我像正常查询一样获取此查询的答案(与不按日期排序的查询速度相同)都会很棒。我尝试将复合查询创建为 nidfield_article_date_format_value 的组合并在查询中使用并没有帮助解决问题。我愿意提供有关该问题的更多信息和任何新建议。

最佳答案

看看您的查询和解释,似乎在 where 子句中使用 n.status=1 会使搜索效率非常低,因为您需要返回连接定义的整个集合,然后应用状态= 1. 尝试从由 WHERE 立即过滤的 term_node 表开始连接,然后立即使连接添加状态条件。试一试,请告诉我进展如何。

 SELECT n.nid, n.title,
           ma.field_article_date_format_value, 
           ma.field_article_summary_value 
      FROM term_node tn
INNER JOIN node n ON n.nid=tn.nid AND n.status=1
INNER JOIN content_type_article ma FORCE INDEX (ix_article_date) ON n.nid=ma.nid 
     WHERE tn.tid= 153 
  ORDER BY ma.field_article_date_format_value DESC 
     LIMIT 0, 11;

关于mysql - 无法优化使用 ORDER BY 子句的 MySQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13851296/

相关文章:

Mysql获取组的最后一个元素

java - mysql命令应该完成哪些流程,Java应该完成哪些流程?

mysql - 仅根据数据而不是日期和时间搜索 MySQL 数据库

mysql - 提供对 phpmyadmin 页面的读/写访问

字符串比较中的C++字符

c++ - 使用 const 成员变量索引数组

linux - Elasticsearch 突然停止工作

mysql - 将 ORDER BY 添加到 LEFT OUTER JOIN

mysql - SQL - 如何使用总和和顺序进行排名?

oracle - 带有 ORDER BY NULL 的 LISTAGG 实际上用作订单标准是什么?