我有以下查询实际上是在一个存储过程中,但我删除它,因为存储过程内部有太多的进展。基本上这是最终结果,需要花费很长时间(超过一分钟)才能运行,我知道原因 - 正如您将从查看解释结果中看到的那样 - 但我无法对其进行排序。
只是为了快速解释这个查询正在做什么。它从与li.nToObjectID = 37
公司“连接”的公司获取所有产品。结果还会返回其他公司的其他信息,如名称,公司ID等。
SELECT DISTINCT
SQL_CALC_FOUND_ROWS
p.id,
p.sTitle,
p.sTeaser,
p.TimeStamp,
p.ExpiryDate,
p.InStoreDate,
p.sCreator,
p.sProductCode,
p.nRetailPrice,
p.nCostPrice,
p.bPublic,
c.id as nCompanyID,
c.sName as sCompany,
m.id as nMID,
m.sFileName as sHighResFileName,
m.nSize,
(
Select sName
FROM tblBrand
WHERE id = p.nBrandID
) as sBrand,
(
Select t.sFileName
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as sFileName,
(
Select t.nWidth
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nWidth,
(
Select t.nHeight
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nHeight,
IF (
(
SELECT COUNT(id) FROM tblLink
WHERE
sType = "company"
AND sStatus = "active"
AND nToObjectID = 37
AND nFromObjectID = u.nCompanyID
),
1,
0
) AS bLinked
FROM tblProduct p
INNER JOIN tblMedia m
ON (
m.nTypeID = p.id AND
m.sType = "product"
)
INNER JOIN tblUser u
ON u.id = p.nUserID
INNER JOIN tblCompany c
ON u.nCompanyID = c.id
LEFT JOIN tblLink li
ON (
li.sType = "company"
AND li.sStatus = "active"
AND li.nToObjectID = 37
AND li.nFromObjectID = u.nCompanyID
)
WHERE c.bActive = 1
AND p.bArchive = 0
AND p.bActive = 1
AND NOW() <= p.ExpiryDate
AND (
li.id IS NOT NULL
OR (
li.id IS NULL
AND p.bPublic = 1
)
)
ORDER BY p.TimeStamp DESC
LIMIT 0, 52
单击此处查看EXPLAIN的输出。抱歉,无法正确格式化。
http://i60.tinypic.com/2hdqjgj.png
最后是此查询中所有表的行数:
tblProducts 数:5392
tblBrand 数:194
tblCompany 数:368
tblUser 数:416
tblMedia 数:5724
tblLink 数:24800
tblThumbnail 数:22207
所以我有两个问题: 1.是否有另一种编写此查询的方法可能会加快速度? 2.对于tblProducts我需要什么索引组合,以便不是所有的行都被搜索到了?
这是删除子查询并使用左连接后的新查询:
SELECT DISTINCT DISTINCT
SQL_CALC_FOUND_ROWS
p.id,
p.sTitle,
p.sTeaser,
p.TimeStamp,
p.ExpiryDate,
p.InStoreDate,
p.sCreator,
p.sProductCode,
p.nRetailPrice,
p.nCostPrice,
p.bPublic,
c.id as nCompanyID,
c.sName as sCompany,
m.id as nMID,
m.sFileName as sHighResFileName,
m.nSize,
brand.sName as sBrand,
thumb.sFilename,
thumb.nWidth,
thumb.nHeight,
IF (
(
SELECT COUNT(id) FROM tblLink
WHERE
sType = "company"
AND sStatus = "active"
AND nToObjectID = 37
AND nFromObjectID = u.nCompanyID
),
1,
0
) AS bLinked
FROM tblProduct p
INNER JOIN tblMedia m
ON (
m.nTypeID = p.id AND
m.sType = "product"
)
INNER JOIN tblUser u
ON u.id = p.nUserID
INNER JOIN tblCompany c
ON u.nCompanyID = c.id
LEFT JOIN tblLink li
ON (
li.sType = "company"
AND li.sStatus = "active"
AND li.nToObjectID = 37
AND li.nFromObjectID = u.nCompanyID
)
LEFT JOIN tblBrand AS brand
ON brand.id = p.nBrandID
LEFT JOIN tblThumbnail AS thumb
ON (
thumb.nMediaID = m.id
AND thumb.sType = 'thumbnail'
)
WHERE c.bActive = 1
AND p.bArchive = 0
AND p.bActive = 1
AND NOW() <= p.ExpiryDate
AND (
li.id IS NOT NULL
OR (
li.id IS NULL
AND p.bPublic = 1
)
)
ORDER BY p.TimeStamp DESC
LIMIT 0, 52;
ALTER TABLE tblThumbnail ADD INDEX (nMediaID,sType) USING BTREE;
ALTER TABLE tblMedia ADD INDEX (nTypeID,sType) USING BTREE;
ALTER TABLE tblProduct ADD INDEX (bArchive,bActive,ExpiryDate,bPublic,TimeStamp) USING BTREE;
完成上述更改后,解释显示现在只搜索tblProduct上的1464行而不是5392。
答案 0 :(得分:1)
这是一个很大的问题。它需要几个步骤来优化它。我将冒昧地提出几个步骤。
第一步。你能摆脱SQL_CALC_FOUND_ROWS并仍然让你的程序正常工作吗?如果是这样,那就这样做。当您指定SQL_CALC_FOUND_ROWS时,它有时意味着服务器必须延迟向您发送结果集的第一行,直到最后一行可用。
第二步。将依赖子查询重构为JOIN。
以下是您可以采用的方法。部分查询看起来像这样......
SELECT DISTINCT SQL_CALC_FOUND_ROWS
p.id,
...
c.id as nCompanyID,
...
m.id as nMID,
...
( /* dependent subquery to be removed */
Select sName
FROM tblBrand
WHERE id = p.nBrandID
) as sBrand,
( /* dependent subquery to be removed */
Select t.sFileName
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as sFileName,
( /* dependent subquery to be removed */
Select t.nWidth
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nWidth,
( /* dependent subquery to be removed */
Select t.nHeight
FROM tblThumbnail t
where t.nMediaID = m.id AND
t.sType = "thumbnail"
) as nHeight,
...
试试这个。请注意品牌和缩略图相关子查询如何消失。您有三个缩略图的从属子查询;它们可以消失在一个JOIN中。
SELECT DISTINCT SQL_CALC_FOUND_ROWS
p.id,
...
brand.sName,
thumb.sFilename,
thumb.nWidth,
thumb.nHeight,
...
FROM tblProduct p
INNER JOIN tblMedia AS m ON (m.nTypeID = p.id AND m.sType = 'product')
... (other table joins) ...
LEFT JOIN tblBrand AS brand ON p.id = p.nBrandID
LEFT JOIN tblMedia AS thumb ON (t.nMediaID = m.id AND thumb.sType = 'thumbnail')
我使用了LEFT JOIN而不是INNER JOIN,因此如果缺少连接的行,MySQL将显示NULL值。
修改强>
您正在使用如下所示的联接模式:
JOIN sometable AS s ON (s.someID = m.id AND s.sType = 'string')
你似乎为几张桌子做了这件事。您可以通过在这些表中创建复合索引来加速JOIN操作。例如,尝试将以下索引添加到tblThumbnail:(sType,nMediaID)。您可以使用此DDL语句执行此操作。
ALTER TABLE tblThumbnail ADD INDEX (sType, nMediaID) USING BTREE
您可以使用相同的连接模式对其他表执行类似的操作。