2

如何优化这个?

SELECT e.attr_id, e.sku, a.value

FROM product_attr AS e, product_attr_text AS a

WHERE e.attr_id = a.attr_id
AND value
IN (
    SELECT value
    FROM product_attr_text 
    WHERE attribute_id = (
        SELECT attribute_id
        FROM eav_attr 
        WHERE attribute_code = 'similar_prod_id' 
    ) 
    AND value != ''

    GROUP BY value
    HAVING (COUNT( value ) > 1 )
)
4

7 回答 7

2
SELECT  e.attr_id, e.sku, a.value
FROM    (
        SELECT  pat.value
        FROM    eav_attr ea
        JOIN    product_attr_text pat
        ON      pat.attribute_id = ea.attribute_id
        WHERE   ea.attribute_code = 'similar_prod_id'
                AND value <> ''
        GROUP BY
                value
        HAVING  COUNT(*) > 1
        ) q
JOIN    product_attr_text AS a
ON      a.value = q.value
JOIN    product_attr AS e
ON      e.attr_id  = a.attr_id

创建索引:

 eav_attr (attribute_code)
 product_attr_text (attribute_id, value)
 product_attr_text (value)
 product_attr (attr_id)
于 2010-10-28T12:17:48.343 回答
1

很难回答...

我唯一能说的是:

  • 看执行计划

  • 使用 IO 统计信息-

看看语句的哪一部分有问题,以及为什么。找出是否可以通过添加索引等来提高性能...

除此之外,我不明白您为什么要使用 group by 子句...

而且,你为什么使用子查询,而不是加入表?(虽然我认为这不会有太大的不同,因为 SQL Server 优化器应该足够聪明以生成相同的执行计划)。

于 2010-10-28T12:10:21.137 回答
1

将第二个内部选择更改为连接:

SELECT e.attr_id, e.sku, a.value
FROM product_attr AS e, product_attr_text AS a
WHERE e.attr_id = a.attr_id
AND value
IN (
    SELECT at.value
    FROM product_attr_text at, eav_attr eat 
    WHERE at.attribute_id = eat.attribute_id 
          AND eat.attribute_code = 'similar_prod_id' 
          AND value != ''
    GROUP BY value
    HAVING (COUNT( value ) > 1 )
)

然后,查看执行计划以了解查询是如何解决的。您可能需要基于该执行计划进行额外的优化(例如,确保attribute_id 字段已编入索引)。

于 2010-10-28T12:16:09.003 回答
1

将其更改为 JOIN。MySQL 没有很好地优化 IN() 子句中的子查询 - 它是每行重新计算的(对于许多行来说效率非常低)

SELECT e.attr_id, e.sku, a.value
FROM product_attr AS e
INNER JOIN product_attr_text AS a ON e.attr_id = a.attr_id
INNER JOIN (SELECT value
    FROM product_attr_text 
    INNER JOIN eav_attr ON eav_attr.attribute_id=product_attr_text.attribute_id
    WHERE attribute_code = 'similar_prod_id'  
    AND value != ''
    GROUP BY value
    HAVING COUNT( value ) > 1 
) AS filter ON filter.value=a.value

转换查询后(您可能需要根据您的架构进行一些更正),EXPLAIN在查询上运行并相应地编制索引。

于 2010-10-28T12:16:50.767 回答
1

弗雷德里克的回答是正确的,但我想提出几点建议:

  • 避免 IN,使用 EXISTS
  • 避免 = (SELECT something from sometable),使用 exists 代替
  • 没用的分组
  • 在 from 子句中使用内连接而不是多个表

但同样,这取决于您的机器/dbms/版本等...所以为了获得最佳性能,您必须比较不同的执行计划

于 2010-10-28T12:17:14.253 回答
1

注意:警惕使用 EAV(实体、属性、值)表设计的设计。由于参照完整性和查询复杂性的原因,它们往往变得非常难以处理。

通过使用进行优化:

  • 加入而不是子选择。
  • 加入符号。
  • 所有列名上的显式表别名。

阶段1:

SELECT e.attr_id, e.sku, a.value
  FROM product_attr AS e JOIN product_attr_text AS a
       ON e.attr_id = a.attr_id
 WHERE a.value IN (
          SELECT p.value
            FROM product_attr_text AS p
            JOIN eav_attr AS v ON p.attribute_id = v.attribute_id
           WHERE v.attribute_code = 'similar_prod_id'
             AND p.value != ''
           GROUP BY value
          HAVING (COUNT( value ) > 1)
          )

阶段2:

SELECT e.attr_id, e.sku, a.value
  FROM product_attr AS e
  JOIN product_attr_text AS a ON e.attr_id = a.attr_id
  JOIN (SELECT p.value
          FROM product_attr_text AS p
          JOIN eav_attr AS v ON p.attribute_id = v.attribute_id
         WHERE v.attribute_code = 'similar_prod_id'
           AND p.value != ''
         GROUP BY value
        HAVING (COUNT( value ) > 1)
       ) AS x ON x.value = a.value
于 2010-10-28T12:27:15.337 回答
0

通过具有...为组使用派生表并将其加入到您需要填充结果的任何表上

于 2010-10-28T12:16:56.147 回答