mysql - 我如何在 MySQL 中优化这个令人困惑的慢查询?

标签 mysql database optimization

我有一张博客文章表,每篇文章都有一个返回其作者的外键。此表中有 < 15,000 个条目。此查询扫描超过 19,000 行(根据 EXPLAIN),需要文件排序(这可能是 MySQL 的常规行为),并花费 400 多毫秒返回 5 行。可能是因为用于检查项目是否实际发布的复杂 WHERE

最亲爱的 Stack Overflow,我怎样才能控制这个查询?

注意:虽然此标准可能需要简化,但所有条件都是必需的。

SELECT      `blog_post.id`, 
            `blog_post.title`,
            `blog_post.author_id`,
            `blog_post.has_been_fact_checked`,
            `blog_post.published_date`,
            `blog_post.ordering`,
            `auth_user.username`,
            `auth_user.email`
FROM        `blog_post` 
INNER JOIN  `auth_user` 
ON          (`blog_post`.`author_id` = `auth_user`.`id`) 
WHERE       (`blog_post`.`is_approved` = True  AND 
             `blog_post`.`has_been_fact_checked` = True  AND 
             `blog_post`.`published_date` IS NOT NULL AND 
             `blog_post`.`published_date` <= '2010-10-25 22:40:05' ) 
ORDER BY    `blog_post`.`published_date` DESC, 
            `blog_post`.`ordering` ASC, 
            `blog_post`.`id` DESC 
LIMIT 5

除了 PK,我在表中还有以下索引:

idx_published_blog_post -> blog_post(is_approved, has_been_fact_checked, published_date)
idx_pub_date -> blog_post(published_date)

EXPLAIN 的输出如下所示:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: blog_post
         type: ref
possible_keys: blog_post_author_id,idx_published_blog_post,idx_pub_date
          key: idx_published_blog_post
      key_len: 4
          ref: const,const
         rows: 19856
        Extra: Using where; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: auth_user
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: blog.blog_post.author_id
         rows: 1
        Extra: Using index
2 rows in set (0.00 sec)

旁注:2010-10-25 22:40:05 只是执行此查询的代码生成的日期。

非常感谢您提供的所有帮助!

最佳答案

MySQL 不支持索引中的 ASC/DESC 子句。

您需要创建一个名为 reverse_ordering 的单独列并将其值设置为 -ordering(前提是 ordering 是一个数值)

然后您可以创建以下索引:

CREATE INDEX ix_blogpost_a_c_p_ro_id ON blog_post (is_approved, has_been_fact_checked, published_date, reverse_ordering, id)

并重写您的查询:

SELECT      `blog_post.id`, 
            `blog_post.title`,
            `blog_post.author_id`,
            `blog_post.has_been_fact_checked`,
            `blog_post.published_date`,
            `blog_post.ordering`,
            `auth_user.username`,
            `auth_user.email`
FROM        `blog_post` 
INNER JOIN  `auth_user` 
ON          `blog_post`.`author_id` = `auth_user`.`id`
WHERE       `blog_post`.`is_approved` = 1 AND 
            `blog_post`.`has_been_fact_checked` = 1 AND 
            `blog_post`.`published_date` <= '2010-10-25 22:40:05'
ORDER BY    `blog_post`.`published_date` DESC, 
            `blog_post`.`reverse_ordering` DESC, 
            `blog_post`.`id` DESC 
LIMIT 5

您可以去掉 IS NULL 检查,因为不等式条件暗示了它。

更新:

您可能还想阅读这篇文章:

关于mysql - 我如何在 MySQL 中优化这个令人困惑的慢查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4020625/

相关文章:

c - Action 捕捉数据的灵活存储和检索

mysql - 多个小尺寸的行与一个较大的行

php - PHP必须检查数据库连接错误

c - 为什么 n++ 比 n=n+1 执行得更快?

PHP - 用户登录后,重定向到存储在数据库中的地址

MySQL使用index_merge和intersect代替ref和where

当明确要求将数据库存储在另一个路径中时,MySQL 会耗尽/root 中的空间

mysql - 无法使用非 root 用户运行 mariadb 镜像的 docker 容器

sql - 如何避免有太多相似的列?

python - scipy:最小化与最小化.标量;返回 F 与返回 F**2;不应该有什么不同吗?