Mysql子查询优化?
Posted
技术标签:
【中文标题】Mysql子查询优化?【英文标题】:Mysql Subquery Optimization? 【发布时间】:2014-05-25 03:15:53 【问题描述】:我可以以任何不同的方式使用此代码来获得更好的性能吗?
我试过这种方式;
SELECT K.id, M.m_id, K.Sil, K.Banli, K.Foto, K.KullaniciAdi, K.Ad, K.Soyad, K.Gender,
(select rate_id,Rate,Zaman from ratings where UyeID=K.id ORDER BY rate_id DESC LIMIT 1)
但我不能做我想做的事。
这是工作代码。给出我想要的结果:
SELECT K.id, M.m_id, K.Sil, K.Banli, K.Foto, K.KullaniciAdi, K.Ad, K.Soyad, K.Gender,
( SELECT R.mr_id FROM mesajlarreply R
WHERE R.CID=M.m_id
ORDER BY R.mr_id DESC LIMIT 1
) as mr_id,
( SELECT R.Mesaj FROM mesajlarreply R
WHERE R.CID=M.m_id
ORDER BY R.mr_id DESC LIMIT 1
) as Mesaj,
( SELECT R.KayitZaman FROM mesajlarreply R
WHERE R.CID=M.m_id
ORDER BY R.mr_id DESC LIMIT 1
) as KayitZaman
FROM mesajlar M, kullanicilar K
WHERE
CASE
WHEN M.K1 = '1' THEN M.K2 = K.id
WHEN M.K2 = '1' THEN M.K1 = K.id
END
AND ( M.K1 = '1' OR M.K2 = '1' )
ORDER BY M.m_id DESC
LIMIT 20
【问题讨论】:
你能发布两个表的结构吗?或者至少请附加有关主键主键的信息 - 这两个表中哪些列是主键? 您的编辑使这看起来是一个新的/不同的查询。如果是这样,您应该能够针对新查询调整我的答案;如果您遇到困难,请发布一个新问题。 @Clockwork-Muse 我发布了一个新问题,但没有人帮助我。我怎样才能做到这一点? ***.com/questions/23901430/… @traBolicEM - 因为您没有展示您面临的新问题。您似乎希望我们为您做所有事情(甚至是微小的编辑)。您应该能够针对您的新问题调整我现有的答案;如果您的问题中有错别字,我很乐意调整我的答案,但如果您更改表格或其他列,我们希望 you 能够自行处理更改。如果我的回答对 this 问题的表现不够好,请在此处发布更多详细信息(例如您拥有的索引、EXPLAIN 计划的结果),以获得更好/额外的帮助。 【参考方案1】:假设子查询的顺序假定是相同的(不是拼写错误),那么三者的组合就是greatest-n-per-group 问题。 mysql 有几个现有的解决方案,如果每组的行数很少,我想我更喜欢this answer 中的样式,对于您的情况,它看起来像这样:
SELECT rToUse.mr_id, rToUse.mesaj, rToUse.kayitZaman
FROM Mesajlarreply rToUse
LEFT JOIN Mesajlarreply rKnockout
ON rKnockout.cId = rToUse.cId AND rToUse.mr_id < rKnockout.mr_id
WHERE rKnockout.mr_id IS NULL
(这是因为当连接行时,具有最大 mr_id
的行不匹配。由于 rKnockout.mr_id IS NULL
为真,所有其他行都将被丢弃)
您使用三个子查询的事实可能是在系统上做一个数字。
您的 CASE
语句计算为一组简单的布尔条件:
(M.k1 = '1' AND M.k2 = K.id) OR (M.k1 <> '1' AND M.k2 = '1' AND M.k1 = K.id)
...我将假设您不会遇到 both k1
和 k2
同时等于 '1'
的情况,因此M.k1 <> '1'
(如果 is 为真,则保留CASE
的语义)将是不必要的。请注意,OR
s 仍然可能是性能痛点。同样,如果这些列中的任何一个实际上是某种数字类型,则连接将首先需要转换,这可能会降低性能。
所以,我可能会从编写这样的查询开始:
SELECT K.id, M.m_id, K.sil, K.banli, K.foto, K.kullaniciAdi, K.ad, K.soyad, K.gender,
R.mr_id, r.mesaj, r.kayitZaman
FROM Mesajlar M
JOIN Kullanicilar K
ON (M.k1 = '1' AND M.k2 = K.id)
OR (M.k2 = '1' AND M.k1 = K.id)
LEFT JOIN (SELECT rToUse.cId, rToUse.mr_id, rToUse.mesaj, rToUse.kayitZaman
FROM Mesajlarreply rToUse
LEFT JOIN Mesajlarreply rKnockout
ON rKnockout.cId = rToUse.cId
AND rToUse.mr_id < rKnockout.mr_id
WHERE rKnockout.mr_id IS NULL) R
ON R.cId = M.m_id
ORDER BY M.m_id DESC
LIMIT 20
(当然,未经测试 - 未提供数据集)
我为子查询使用了LEFT JOIN
来保留给定的数据语义。如果您有所有案例的行(或只关心那些有的人),则可以将其更改为(INNER) JOIN
。根据您的数据集的布局方式(以及您有/没有的索引),这可能不会表现得更好,但这通常对优化器应该更友好。
【讨论】:
以上是关于Mysql子查询优化?的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 子查询优化 - where not in(子查询)