MySQL:指数时参加表不被用(性能优化问题)
-
16-10-2019 - |
题
我需要优化下查询:
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
解释选择,让我以下结果:
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
为什么首先把文章和随后的博客?这是因为博客有多个条目?和我如何可以改善查询,以便的articlepost可以使用的一个指数?
更新: 一个指标是设在博客.date_created.除去的博客.标题,如条件和date_published <=NOW()没有做任何事情。
当我删除了"文章。id作为民遭受"它可以使用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
解决方案
我仔细看看查询并可能可以重新设计。这里是我的意思是:
限制需0,50部分的查询似乎是由繁忙的在查询最后一个。
你可以改善布局的查询通过执如下:
步骤1)创建一个内联的查询,以收集只键。在这种情况下,身份证对于博客.
步骤2)规定任何在那里,以便通过和组通过的条款在线查询带来的钥匙。
步骤3)关税的限制条款作为最后的步骤使在线查询。
步骤4)加入在线查询与博文表在该事件中,你需要额外的列从博文为,应升级授权表,使之blostpost
步骤5)中加入这个新的博客,应升级授权表,使之与本条款表。
步骤1-3的是创建一个应升级授权表,使之与完全50行和包括博文id。然后,执行所有加入死的最后一次。
这些步骤应用到你原来的查询,你应该有这样的:
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;
因为你编的问题,并指出,将删除一样,现在你的查询应该看起来更像这样:
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;
一语中的[东西省略],如果你什么都不需要从其他博客比键,然后您的查询应该是这样的:
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;
警告
确保建立一个指数涉及的列有删除,可见,date_created如下:
ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);
给它一试试!
其他提示
你在那里的条件 blogposts.title LIKE '%{de}%'
会造成一个完整的表格的扫描的 博客 表。它是可能的MySQL数字扫描第6915文章更加有效。
如何来改善它,可能会添加一个索引 博客 使用 date_created
或 date_published
并添加一个范围内到那里条件(比其他的东西 <=NOW())
和博客.标题LIKE'%{de}%' --无用的优化(导致野卡)
那里的博客.删除=0 和博客.visible=1 --好:如果他们不应当显示,获得他们的表格。
和博客.date_published <=NOW() 为了通过博客.date_created DESC 限制0,50 -这导致了需要索引(date_published) (但是,像和标志可以防止这种指数从被使用。)
请提供 显示CREATE TABLE...;显示表的状态...;
非常感谢你:)
我给它一试发现,实际上你的最后评论的有关指数的东西我需要的。有时这只是一些小的改进,这是需要...;) 比较:
旧的查询:
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
新的查询:
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
现在没有该索引提及:
老解释的结果:
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
新的解释的结果:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ALL deleted,visible,date_published deleted 1 28198 Using filesort
解释的结果与指数上的老查询:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE blogposts ref PRIMARY,deleted,visible,date_published,deleted_vis... deleted_visible_date_created 2 const,const 27771 Using where
1 SIMPLE articles ref blogposts_id blogposts_id 4 db.blogposts.id 1
解释的结果与索引新的查询:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ref deleted,visible,date_published,deleted_visible_dat... deleted_visible_date_created 2 27771 Using where
速度在旧的查询,而无需用指数: 0.1835/0.0037
速度在新的查询,而无需用指数: 0.1883/0.0035
因为只是边际differency之间的旧的新的查询,我喜欢仍然使用旧的查询,但有的指标。但是我将记住这一点,因为如果有一天老的查询是太慢:)
什么是有趣的,我知道,你怎么有这个想法设置指这样吗?我认为,我发表这个问题,我还试图与deleted_visible但不是date_created我用date_published(因为它在那里的条款)...
谢谢:)
更新通过RolandoMySQLDBA2011-05-19 13:03
什么把它放到我是在哪里和秩序的条款。
在其中的条款,删除(0)和可见(1)是静态的价值观。在通过条款,date_created是喜欢移动的目标之间的所有行删除=0和visible=1个。所以,我放的静态变量在前面的索引,然后再运动目标的最后指标。通常,这一部分的基本原则重构SQL发言。你需要的索引,将支持你在哪里,小组通过的,并以条款。