4

我想优化一条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。

Edit2:表:furnizorlist 42,751 条记录表:distribitems 72,290 条记录

4

1 回答 1

1

不完全确定,但这里有几点很有帮助,如果你要使用内部表(你是第一个例子) - 你真的必须尝试缩小它的拉回范围。这可能意味着要编写一些多余的 where 子句。例如,“where order_dt is between 2001 and 2002”可能会出现在较小的内部表和主查询中。为什么?因为在某些情况下无法优化内部表 - 导致服务器临时检索数百万行,仅用于您需要的少数行。

另外,我注意到您的一个连接中的字符串函数“LEFT(f.denumire, 450))”

在连接期间应避免使用任何类型的功能,这会迫使服务器(一个接一个)评估每条记录。它无法优化。这有点类似于为什么您应该始终使用主键进行连接,但更耗时.. 最好坚持使用“like” = AND、NOT、OR、IN.. 等。

于 2012-11-01T06:44:30.443 回答