使用 from 中的子查询优化 SQL
Posted
技术标签:
【中文标题】使用 from 中的子查询优化 SQL【英文标题】:Optimize SQL with subquery in from 【发布时间】:2012-10-14 11:50:13 【问题描述】:我想优化一条SQL语句,下面是原来的。
SELECT DISTINCT
p.productID,
p.filename,
p.model,
p.code,
p.manufacturerID,
f2.manufacturerName,
m.manufacturerName,
CONCAT('INSERT INTO distribItems(productID, manufacturer, code, distributorText) VALUES (',
CAST(p.productID AS CHAR),
', \'',
f2.manufacturerName,
'\', \'',
f2.code,
'\', \'',
f2.denumire,
'\') ;') INS
FROM
(SELECT
f.manufacturerName, f.categoryName, f.code, f.denumire, f.code_2
FROM
furnizorlist f
LEFT JOIN distribitems d ON
(d.manufacturer = f.manufacturerName
AND (d.code = f.code OR d.manufacturer LIKE 'DELL')
AND d.distributorText = LEFT(f.denumire, 450))
WHERE
productID IS NULL) f2,
products p,
manufacturers m
WHERE
f2.code_2 <> ''
AND (f2.code_2 = p.code_2 OR f2.code_2 = p.model_2)
AND p.manufacturerID = m.manufacturerID
AND m.manufacturerName = f2.manufacturerName
AND m.manufacturerName != 'Compatibil'
AND p.code != '1'
ORDER by p.filename ASC;
在我的电脑上大约需要 34 秒。
我的想法是将子查询编写为 Join 并在 Where 子句中设置条件。
这是我难以置信的快速 SQL:
SELECT DISTINCT
p.productID,
p.filename,
p.model,
p.code,
p.manufacturerID,
f.manufacturerName,
m.manufacturerName,
CONCAT('INSERT INTO distribItems(productID, manufacturer, code, distributorText) VALUES (',
CAST(p.productID AS CHAR),
', \'',
f.manufacturerName,
'\', \'',
f.code,
'\', \'',
f.denumire,
'\') ;') INS
FROM
furnizorlist f,
distribitems d,
#subquery end
products p,
manufacturers m
WHERE
d.manufacturer = f.manufacturerName
AND (d.code = f.code OR d.manufacturer LIKE 'DELL')
AND d.distributorText = LEFT(f.denumire, 450)
AND d.productID IS NULL
#subquery condions end (f and d tables)
# the next is a subquery result:
AND f.code_2 <> ''
AND (f.code_2 = p.code_2 OR f.code_2 = p.model_2)
AND p.manufacturerID = m.manufacturerID
AND m.manufacturerName = f.manufacturerName
AND m.manufacturerName != 'Compatibil'
AND p.code != '1'
ORDER by p.filename ASC;
如果我写信给explain improved_sql
,我会看到 Impossible WHERE 列。
我试过但找不到为什么这是不可能的。我检查了字段的兼容性:没有需要将 int 与 varchar 进行比较等情况。我找不到任何重大错误,这就是我在这里的原因。
WHERE 子句中是否存在逻辑错误?比如要求一个字段是1
,然后是2
?
以 ID 结尾的字段是 INT 以 NAME 结尾的字段,代码为 varchar (255) 带文本的字段为 450 和 8192 varchar(仅在一处使用)
翻译:“denumire”的意思是“描述”——或者类似的东西:)
不确定服务器端运行的是哪个版本的mysql,可能是5。
如果我有充分的理由,我可以建议更改表结构,可能会调整代码。
编辑:
不可能从这里来:
EXPLAIN
SELECT
f.manufacturerName,
f.categoryName,
f.code,
f.denumire,
f.code_2
FROM
furnizorlist f
INNER JOIN
distribitems d ON (d.manufacturer = f.manufacturerName
AND (d.code = f.code
OR d.manufacturer LIKE 'DELL')
AND d.distributorText = LEFT(f.denumire, 450))
WHERE
productID IS NULL
备注:INNER JOIN ,不是 LEFT JOIN。
编辑2: 表:furnizorlist 42,751 条记录 表:分布 72,290 条记录
【问题讨论】:
1) 您将left join
修改为 inner join
2) 您是否收到与第一个 sql 相同的消息?
现在两者都有空结果,所以是的:) - 但没有观察到左连接的重要性,谢谢
子查询中的 23087 条记录为 LEFT JOIN,0 为 INNER JOIN ...这就是为什么这么快? :) 并且从那里出现了 Impossible WHERE (explain 不完全确定,但如果您要使用内表(您是第一个示例),这里有几点很有帮助 - 您确实必须尝试缩小它的回退范围。这可能意味着要编写一些多余的 where 子句。例如,“where order_dt is between 2001 and 2002”可能会出现在较小的内部表和主查询中。为什么?因为在某些情况下无法优化内部表 - 导致服务器临时检索数百万行,仅用于您需要的少数。
另外,我注意到您的一个连接“LEFT(f.denumire, 450))”中有一个字符串函数
在连接期间应避免使用任何类型的功能,这会迫使服务器(一个接一个)评估每条记录。它无法优化。这与为什么您应该始终使用主键进行连接有些相似,但更耗时.. 最好坚持使用“like” = AND、NOT、OR、IN.. 等。
【讨论】:
谢谢,我下午试试以上是关于使用 from 中的子查询优化 SQL的主要内容,如果未能解决你的问题,请参考以下文章