OR子句减慢SQL查询速度

时间:2013-12-17 08:05:57

标签: mysql sql performance

我需要您对下面的查询的帮助,该查询需要2分钟以上才能返回结果:

SELECT 
    p.weight, 
    o.login,
    o.date, 
    o.s_address, 
    o.s_city, 
    o.s_county, 
    o.s_state, 
    o.s_country, 
    o.s_zipcode, 
    o.phone, 
    c.categoryid, 
    c.category, 
    o.orderid, 
    p.product product_name, 
    p.productcode sku, 
    d.amount, 
    v.value emplacement, 
    ( SELECT ev.value FROM xcart_extra_field_values ev LEFT JOIN xcart_extra_fields ef ON ef.fieldid=ev.fieldid WHERE ev.productid = d.productid AND ef.field = 'a_type' LIMIT 1 ) type, 
    o.customer_notes, 
    o.membership, 
    o.s_firstname, 
    o.s_lastname, 
    o.phone, 
    d.price, 
    o.email 
FROM `xcart_orders` o 
LEFT JOIN `xcart_shipping` s ON s.shippingid=o.shippingid 
LEFT JOIN `xcart_order_details` d ON d.orderid=o.orderid 
LEFT JOIN `xcart_products` p ON p.productid=d.productid 
LEFT JOIN `xcart_products_categories` pc ON pc.productid=p.productid 
LEFT JOIN `xcart_categories` c ON c.categoryid=pc.categoryid 
LEFT JOIN `xcart_extra_field_values` v ON v.productid=p.productid 
LEFT JOIN `xcart_extra_fields` f ON f.fieldid=v.fieldid 
WHERE o.shippingid IN ( SELECT DISTINCT shippingid FROM `xcart_rafale_shipping` WHERE rafale='1' ) 
AND ( 
    SELECT COUNT(*) 
    FROM `xcart_order_details` d2 
    LEFT JOIN `xcart_products_categories` pc2 ON pc2.productid=d2.productid 
    WHERE d2.orderid=o.orderid 
    AND pc2.categoryid NOT IN ( SELECT DISTINCT ac2.categoryid FROM `xcart_rafale_aggregation_categories` ac2 WHERE ac2.aggregationid='12' ) 
) = 0 
AND ( 
    ( o.date BETWEEN '1386802800' AND '1386889199' ) 
    OR (o.orderid IN ('44', '55', '66')) 
) 
AND o.orderid NOT IN ('11', '22', '33', '123', '458') 
AND o.paid = 'Y' 
AND o.status <> 'F' 
AND o.status <> 'Q' 
AND o.status <> 'I' 
AND f.field = 'emplacement' 
AND pc.main = 'Y' 
ORDER BY v.value ASC, p.productcode ASC 
LIMIT 100

问题可能来自以下条款

AND ( 
    ( o.date BETWEEN '1386802800' AND '1386889199' ) 
    OR (o.orderid IN ('44', '55', '66')) 
)

因为当我删除OR (o.orderid IN ('44', '55', '66'))

时查询执行得更快

o.date和o.orderid列上有索引

我使用下面的查询灵感来自@ Clockwork-Muse的回复:

SELECT 
    p.weight, 
    o.login,
    o.date, 
    o.s_address, 
    o.s_city, 
    o.s_county, 
    o.s_state, 
    o.s_country, 
    o.s_zipcode, 
    o.phone, 
    c.categoryid, 
    c.category, 
    o.orderid, 
    p.product product_name, 
    p.productcode sku, 
    d.amount, 
    v.value emplacement, 
    ( SELECT ev.value FROM xcart_extra_field_values ev LEFT JOIN xcart_extra_fields ef ON ef.fieldid=ev.fieldid WHERE ev.productid = d.productid AND ef.field = 'a_type' LIMIT 1 ) type, 
    o.customer_notes, 
    o.membership, 
    o.s_firstname, 
    o.s_lastname, 
    o.phone, 
    d.price, 
    o.email
FROM `xcart_order_details` d
INNER JOIN (SELECT *
            FROM `xcart_orders`
            WHERE (
                orderid IN ('44', '55', '66') 
                OR (`date` >= '1386802800' AND `date` <= '1386889199')
            )
            ) o
        ON o.orderid = d.orderid
INNER JOIN (SELECT DISTINCT shippingid
            FROM `xcart_rafale_shipping`
            WHERE rafale = '1') rf
        ON rf.shippingid = o.shippingid
INNER JOIN `xcart_shipping` s ON s.shippingid=o.shippingid  
INNER JOIN `xcart_products` p ON p.productid=d.productid
INNER JOIN (SELECT *
            FROM `xcart_products_categories`
            WHERE main = 'Y') pc
        ON pc.productid=p.productid
LEFT JOIN `xcart_categories` c ON c.categoryid=pc.categoryid
LEFT JOIN `xcart_extra_field_values` v ON v.productid=p.productid  
LEFT JOIN `xcart_extra_fields` f ON f.fieldid=v.fieldid
WHERE NOT EXISTS ( 
    SELECT d2.orderid 
    FROM `xcart_order_details` d2 
    LEFT JOIN `xcart_products_categories` pc2 ON pc2.productid=d2.productid 
    WHERE d2.orderid=o.orderid 
    AND pc2.categoryid NOT IN ( SELECT DISTINCT ac2.categoryid FROM `xcart_rafale_aggregation_categories` ac2 WHERE ac2.aggregationid='12' ) 
) 
AND o.orderid NOT IN ('11', '22', '33', '123', '458') 
AND o.paid = 'Y'
AND o.status NOT IN ('F', 'Q', 'I')
AND f.field = 'emplacement'

3 个答案:

答案 0 :(得分:2)

最有可能帮助你的是确保你在xcart_orders.orderid上有一个索引,如果你确定查询的一部分让它变慢了。

答案 1 :(得分:2)

除了您的查询所遇到的任何其他问题,或者它可能需要的索引之外,它还在做更多的工作而不是它需要的工作;这是一个稍微调整过的版本,可能运行得更快:

SELECT 
    p.weight, 
    o.login,
    o.date, 
    o.s_address, 
    o.s_city, 
    o.s_county, 
    o.s_state, 
    o.s_country, 
    o.s_zipcode, 
    o.phone, 
    c.categoryid, 
    c.category, 
    o.orderid, 
    p.product product_name, 
    p.productcode sku, 
    d.amount, 
    v.value emplacement, 
    (SELECT ev.value 
     FROM xcart_extra_field_values ev 
     INNER JOIN xcart_extra_fields ef 
             ON ef.fieldid = ev.fieldid
                AND ef.field = 'a_type'  
     WHERE ev.productid = d.productid) type, 
    o.customer_notes, 
    o.membership, 
    o.s_firstname, 
    o.s_lastname, 
    o.phone, 
    d.price, 
    o.email 
FROM `xcart_orders` o
INNER JOIN (SELECT DISTINCT shippingid
            FROM `xcart_rafale_shipping`
            WHERE rafale = '1') rf
        ON rf.shippingid = o.shippingid
LEFT JOIN `xcart_shipping` s 
       ON s.shippingid = o.shippingid 
LEFT JOIN `xcart_order_details` d 
       ON d.orderid = o.orderid 
LEFT JOIN `xcart_products` p 
       ON p.productid = d.productid 
LEFT JOIN `xcart_products_categories` pc 
       ON pc.productid = p.productid
          AND pc.main = 'Y'
LEFT JOIN `xcart_categories` c 
       ON c.categoryid = pc.categoryid 
LEFT JOIN `xcart_extra_field_values` v 
       ON v.productid = p.productid 
LEFT JOIN `xcart_extra_fields` f 
       ON f.fieldid = v.fieldid
          AND f.field = 'emplacement'  
WHERE NOT EXISTS (SELECT *
                  FROM `xcart_products_categories` pc2
                  LEFT JOIN `xcart_rafale_aggregation_categories` ac2
                         ON ac2.categoryid = pc2.categoryid
                            AND ac2.aggregationid = '12'
                  WHERE pc2.productid = d.productid
                        AND ac2.categoryid IS NULL)
AND ((o.date >= '1386802800' AND o.date <'1386889200') 
     OR o.orderid IN ('44', '55', '66')) 
AND o.orderid NOT IN ('11', '22', '33', '123', '458') 
AND o.paid = 'Y' 
AND o.status NOT IN ('F', 'Q', 'I')        
ORDER BY v.value ASC, p.productcode ASC 
LIMIT 100

其他一些事情 -

  1. LEFT JOIN子句中有条件WHERE - 这实际上会将它们变成INNER JOIN s。我已将相关条件移至联接中,这可能会改变您的结果。如果您想要实际INNER JOIN,只需更改/删除该字词即可。这就是为什么最好在可能的情况下在连接中加入所有条件。
  2. 日期/时间/时间戳(即使未存储为该类型)是“测量” - 所有测量在逻辑上在记录中有一些不精确性;为了反映这一点,请使用“下限包含,上限独占”(a >= x < b,需要翻转为负值)进行比较。为了保持一致性,我还建议将其用于整数计数。
  3. 如果没有ORDER BY子句,对LIMIT(或类似语句)的任何使用都会返回基本上无法控制的结果。如果只需要一个值,则必须执行以下操作之一 - 1)使用聚合(MAX()等),2)编写查询/构造数据库,使得只有一个值将满足标准,3)为“选择位置x”类型结构的使用提供相关的ORDER BY。如果不这样做,将导致您的查询在您最不期望的情况下返回意外结果(并且不会发出警告)。在这种情况下,我发现EAV表中的值不可能超过一个实例(基本上是#2)。
  4. 您的原始查询包含一个相当混淆的双重否定(SELECT COUNT(*) ... = 0))。不幸的是,在不了解更多关于数据/表格模式的本质的情况下,我无法真正消除双重否定(尽管我可以使其更明显。为了未来的维护者,请尽可能避免双重否定。在这种情况下,这是因为您(可能过度)自由使用LEFT - 加入 - 您确定不需要吗?

答案 2 :(得分:0)

尝试此查询,我尝试了所有subquerys放入连接:

SELECT 
    p.weight, 
    o.login,
    o.date, 
    o.s_address, 
    o.s_city, 
    o.s_county, 
    o.s_state, 
    o.s_country, 
    o.s_zipcode, 
    o.phone, 
    c.categoryid, 
    c.category, 
    o.orderid, 
    p.product product_name, 
    p.productcode sku, 
    d.amount, 
    v.value emplacement, 
    evv.Value AS type, 
    o.customer_notes, 
    o.membership, 
    o.s_firstname, 
    o.s_lastname, 
    o.phone, 
    d.price, 
    o.email 
FROM `xcart_orders` o 
LEFT JOIN `xcart_shipping` s ON s.shippingid=o.shippingid 
LEFT JOIN `xcart_order_details` d ON d.orderid=o.orderid 
LEFT JOIN `xcart_products` p ON p.productid=d.productid 
LEFT JOIN `xcart_products_categories` pc ON pc.productid=p.productid 
LEFT JOIN `xcart_categories` c ON c.categoryid=pc.categoryid 
LEFT JOIN `xcart_extra_field_values` v ON v.productid=p.productid 
LEFT JOIN `xcart_extra_fields` f ON f.fieldid=v.fieldid 
JOIN (SELECT DISTINCT shippingid 
      FROM `xcart_rafale_shipping`
      WHERE rafale='1') rs
 ON rs.shippingid = o.shippingid
JOIN (SELECT d2.orderid, COUNT(*) as cnt
    FROM `xcart_order_details` d2 
    LEFT JOIN `xcart_products_categories` pc2 ON pc2.productid=d2.productid 
    LEFT JOIN `xcart_rafale_aggregation_categories` ac2
      ON  ac2.aggregationid='12'
      AND ac2.categoryid = pc2.categoryid
    WHERE ac2.categoryid is null
    GROUP BY d2.orderid
) dd2
  ON dd2.orderid=o.orderid 
  AND dd2.cnt = 0
LEFT JOIN (SELECT ev.productid, MAX(ev.value) as 'Value'
           FROM xcart_extra_field_values ev
           LEFT JOIN xcart_extra_fields ef ON ef.fieldid=ev.fieldid
           WHERE ef.field = 'a_type'
           GROUP BY ev.productid) evv
 ON evv.productid = d.productid
WHERE (( o.date BETWEEN '1386802800' AND '1386889199' ) 
               OR (o.orderid IN ('44', '55', '66')) 
       ) 
AND o.orderid NOT IN ('11', '22', '33', '123', '458') 
AND o.paid = 'Y' 
AND o.status NOT IN ('F', 'Q', 'I')
AND f.field = 'emplacement' 
AND pc.main = 'Y' 
ORDER BY v.value ASC, p.productcode ASC 
LIMIT 100