MySQL:加入未使用的表时的索引(性能优化问题)

Mic*_*bel 6 mysql performance index query optimization

我需要优化以下查询:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
Run Code Online (Sandbox Code Playgroud)

EXPLAIN SELECT 给我以下结果:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Run Code Online (Sandbox Code Playgroud)

为什么它先是文章,然后是博客文章?是因为博客文章有更多条目吗?以及如何改进查询以便文章帖子可以使用索引?

更新: 在 blogposts.date_created 上设置了索引。删除 blogposts.title LIKE 条件和 date_published <= NOW() 不会做任何事情。

当我删除“ articles.id AS articleid ”时,它可以在文章上使用 blogpost_id 索引......对我来说听起来很奇怪,有人知道为什么吗?(因为我真的需要它..)

新的解释如下所示:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  articles    index blogpost_id blogpost_id    4    NULL    6915    Using index; Using temporary; Using filesort
1   SIMPLE  blogposts   eq_ref  PRIMARY PRIMARY 4   articles.blogpost_id    1   Using where
Run Code Online (Sandbox Code Playgroud)

Rol*_*DBA 4

我仔细查看了该查询,您也许可以重新设计它。我的意思是:

查询的 LIMIT 0,50 部分似乎在最后的查询中变得繁忙。

您可以通过执行以下操作来改进查询的布局:

步骤 1) 创建内联查询以仅收集键。在本例中,是博客帖子的 ID。

步骤 2) 对带有键的内联查询施加任何 WHERE、ORDER BY 和 GROUP BY 子句。

步骤 3) 引入 LIMIT 子句作为进行内联查询的最后一步。

步骤 4) 如果您需要 blogpost 中的其他列作为 blospost 临时表,请将内联查询与 blogpost 表连接起来

步骤 5) 将这个新博客文章与文章表连接起来。

步骤 1-3 旨在创建一个恰好包含 50 行并包含博客文章 ID 的临时表。然后,最后执行所有 JOIN。

将这些步骤应用于您的原始查询后,您应该得到以下结果:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
  SELECT B.*
  FROM
  (
    SELECT id FROM blogposts
    WHERE date_published <= NOW()
    AND deleted = 0 AND visible = 1
    AND title LIKE '%{de}%'
    ORDER BY date_created DESC
    LIMIT 0,50
  ) A
  INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
Run Code Online (Sandbox Code Playgroud)

由于您编辑了问题并声明您将删除 LIKE,现在您的查询应该看起来更像这样:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
  SELECT B.*
  FROM
  (
    SELECT id FROM blogposts
    WHERE date_published <= NOW()
    AND deleted = 0 AND visible = 1
    ORDER BY date_created DESC
    LIMIT 0,50
  ) A
  INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
Run Code Online (Sandbox Code Playgroud)

在短语[省略的东西]中,如果除了键之外不需要博客文章中的任何内容,那么您的查询应如下所示:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
  SELECT id FROM blogposts
  WHERE date_published <= NOW()
  AND deleted = 0 AND visible = 1
  ORDER BY date_created DESC
  LIMIT 0,50
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
Run Code Online (Sandbox Code Playgroud)

警告

确保您构建的索引涉及已删除、可见和 date_created 列,如下所示:

ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);
Run Code Online (Sandbox Code Playgroud)

试一试 !!!