MySQL查询SLOW不知道如何优化
我认为我对60 GB RAM 10核SSD硬件没问题
您好,我在查询以下查询的Mysql上运行缓慢时遇到了一个大问题:
# Thread_id: 1165100 Schema: back-Alvo-11-07-19 QC_hit: No
# Query_time: 9.015205 Lock_time: 0.000188 Rows_sent: 1 Rows_examined: 2616880
# Rows_affected: 0
SET timestamp=1568549358;
SELECT count(*) as total_rows FROM(
(SELECT m.*
FROM phpfox_channel_video AS m
INNER JOIN phpfox_channel_category AS mc
ON(mc.category_id = mc.category_id)
INNER JOIN phpfox_channel_category_data AS mcd
ON(mcd.video_id = m.video_id)
WHERE m.in_process = 0 AND m.view_id = 0
AND m.module_id = 'videochannel'
AND m.item_id = 0 AND m.privacy IN(0)
AND mcd.category_id = 17
GROUP BY m.video_id
ORDER BY m.time_stamp DESC
LIMIT 12
)) AS m
JOIN phpfox_user AS u
ON(u.user_id = m.user_id);
此查询运行非常缓慢,您可以看到9秒
在寻找优化查询的在线帮助时,总是谈论添加索引,
正如您在下面的解释说明中所看到的,我已经有索引
你们对我应该提高查询速度的想法有何想法?我不是DB家伙很难解决这个问题。这是一个网站,拥有40万个视频。
谢谢
答案 0 :(得分:1)
该说明表明您未在表phpfox_channel_video as m
上使用索引,并且正在表phpfox_channel_category AS mc
上使用临时索引,这意味着它没有在使用索引,而是在构建一个首先进行索引,这需要花费大量时间。
此外,表phpfox_channel_category_data AS mcd
的索引可能更好。
您需要的索引是:
CREATE INDEX idx_cat_data_video_id ON phpfox_channel_category_data
(category_id, video_id);
CREATE INDEX idx_channel_cat_id ON phpfox_channel_category (category_id);
CREATE INDEX idx_video_mult ON phpfox_channel_video
(in_process, view_id, module_id, item_id, privacy, video_id, time_stamp);
答案 1 :(得分:1)
m.*
,请不要获取COUNT(*)
。phpfox_channel_category
是多对多映射表,请按照http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table中的提示进行操作m
需要INDEX(in_process, view_id, module_id, item_id, privacy)
的任何顺序。避免使用GROUP BY
:
INNER JOIN phpfox_channel_category AS mc ON(mc.category_id = mc.category_id)
INNER JOIN phpfox_channel_category_data AS mcd ON(mcd.video_id = m.video_id)
AND mcd.category_id = 17
GROUP BY m.video_id
->(类似)
AND EXISTS(
SELECT 1
FROM phpfox_channel_category AS mc
JOIN phpfox_channel_category_data AS mcd
ON mcd.video_id = mc.video_id
WHERE mcd.video_id = 17
AND mc.video_id = m.video_id
)
答案 2 :(得分:0)
让我们确保我们正在优化正确的查询。我建议我们在ON
子句中检查这种情况:
mc.category_id = mc.category_id
我们知道mc
中的每一行都将为TRUE,且其非空值为category_id
。我们可以将该条件表示为:
mc.category_id IS NOT NULL
这意味着联接几乎是交叉联接; m
返回的每一行都与mc
返回的每一行匹配。也就是说,我们可以得到等效的结果:
FROM phpfox_channel_video m
JOIN phpfox_channel_category mc
ON mc.category_id IS NOT NULL
我怀疑这不是我们追求的结果。我认为我们的意思是匹配m.category_id
。但这只是一个猜测。
如果video_id
列是m
上的PRIMARY KEY或UNIQUE KEY,则可以通过使用带有相关子查询的EXISTS来避免创建重复行的联接,从而避免潜在的昂贵GROUP BY
操作。如果我们可以避免生成具有重复值video_id
的中间结果,那么就可以避免需要执行GROUP BY
。
此外,对于内联视图查询,我们可以只返回所需的表达式,而不是返回所有列*
。在外部查询中,唯一引用的列是user_id
。
所以我们可以这样写:
SELECT COUNT(*) AS total_rows
FROM (
SELECT m.user_id
FROM phpfox_channel_video m
WHERE EXISTS ( SELECT 1
FROM phpfox_channel_category mc
WHERE mc.category_id = m.category_id
-- mc.category_id = mc.category_id -- <original
)
AND EXISTS ( SELECT 1
FROM phpfox_channel_category_data mcd
WHERE mcd.video_id = m.video_id
AND mcd.category_id = 17
)
AND m.in_process = 0
AND m.view_id = 0
AND m.module_id = 'videochannel'
AND m.item_id = 0
AND m.privacy IN (0)
ORDER BY m.time_stamp DESC
LIMIT 12
) d
JOIN phpfox_user u
ON u.user_id = d.user_id
为了进行调整,m
的最佳索引将包含具有相等谓词的前导列,其后是time_stamp
列,这样我们就可以避免执行“使用文件排序”操作,ORDER BY
可以通过按索引顺序返回行来满足。看来我们需要对行进行排序的原因是为了LIMIT子句。
... ON phpfox_channel_video (in_process, view_id, item_id, module_id
, time_stamp, video_id, ... )
另外两个表,我们希望索引的前导列具有相等谓词
... ON phpfox_channel_category_data (video_id, category_id, ...)
... ON phpfox_channel_category ( category_id, ... )
注意:
(尚不清楚为什么我们需要内联视图,并且我们延迟了user_id
引用的联接。然后,整个查询的重点对我来说并不很明显;我是只是根据给定的SQL提供了对条件category_id
的更改的重写。)
以上假设category_id
中存在m
列,并且它是一对多关系。
但是如果这不是真的...如果mcd
表实际上是联结表,则解决了视频和类别之间的多对多关系,因此联接条件本来应该是
mcd.category_id = mc.category_id
^
然后,我们希望将上面查询中的WHERE EXISTS
和AND EXISTS
替换为单个相关子查询。像这样:
SELECT COUNT(*) AS total_rows
FROM (
SELECT m.user_id
FROM phpfox_channel_video m
WHERE EXISTS ( SELECT 1
FROM phpfox_channel_category mc
JOIN phpfox_channel_category_data mcd
ON mcd.category_id = mc.category_id
WHERE mcd.video_id = m.video_id
AND mcd.category_id = 17
)
AND m.in_process = 0
AND m.view_id = 0
AND m.module_id = 'videochannel'
AND m.item_id = 0
AND m.privacy IN (0)
ORDER BY m.time_stamp DESC
LIMIT 12
) d
JOIN phpfox_user u
ON u.user_id = d.user_id