基于查询计划优化MySQL查询的建议

时间:2014-11-03 11:06:31

标签: mysql sql

这是我在MySQL数据库上运行的查询。查询占用了更多时间,因为我们在订单表中有更多的记录。请根据查询计划建议优化查询的提示。

  

的MySQL>解释SELECT DISTINCT   dt.customer_id,dt.email,dt.title,dt.fname,dt.lname,DT。   work_phone,dt.mobile_phone,dt.home_phone,dt.blacklist_reason,DT。   域,dt.domain_group,dt.my_account_flag,dt.marketing_preference,DT。   城市,dt.address1,dt.address2,dt.state,DT。   country,dt.zip,dt.country_code FROM(SELECT   cc.customer_id,cc.email,cc.title,cc.fname,cc.lname,   cc.work_phone,cc.mobile_phone,cc.home_phone,cc.blacklist_reason,   cc.domain,cc.domain_group,cc.my_account_flag,cc.marketing_preference,   ca.city,ca.address1,ca.address2,ca.state,   ca.country,ca.zip,ca.country_code,odd.order_date FROM customer cc   INNER JOIN customer_address ca ON cc.customer_id = ca.customer_id left   外连接order_delivery_details奇数   cc.customer_id = odd.customer_id WHERE cc.lname ='XXXXXX'和
  ca.address_purpose ='XXXX'和(cc.domain in('XXXXXX_IE')||   cc.domain_group in('XXXXX','YYYYYY'))order by odd.order_date   desc)dt LIMIT 0,500;

SQL:

SELECT 
    DISTINCT dt.customer_id,
    dt.email,
    dt.title,
    dt.fname,
    dt.lname,
    dt. work_phone,
    dt.mobile_phone,
    dt.home_phone,
    dt.blacklist_reason,
    dt. domain,
    dt.domain_group,
    dt.my_account_flag,
    dt.marketing_preference,
    dt. city,
    dt.address1,
    dt.address2,
    dt.state,
    dt. country,
    dt.zip,
    dt.country_code 
    FROM (
        SELECT 
            cc.customer_id,
            cc.email,
            cc.title,
            cc.fname,
            cc.lname, 
            cc.work_phone,
            cc.mobile_phone,
            cc.home_phone,
            cc.blacklist_reason, 
            cc.domain,
            cc.domain_group,
            cc.my_account_flag,
            cc.marketing_preference, 
            ca.city,
            ca.address1,
            ca.address2,
            ca.state, 
            ca.country,
            ca.zip,
            ca.country_code,
            odd.order_date 
        FROM 
            customer cc 
        INNER JOIN customer_address ca ON cc.customer_id=ca.customer_id 
        left outer join order_delivery_details odd on cc.customer_id=odd.customer_id 
        WHERE   cc.lname = 'XXXXXX' 
        and     ca.address_purpose='XXXX'   
        and  ( cc.domain in ( 'XXXXXX_IE' ) 
            or cc.domain_group in  ( 'XXXXX' , 'YYYYYY' ) 
            )   
        order by odd.order_date desc
    ) dt 
    LIMIT 0,500;

enter image description here

感谢您的回复。我无法在子查询之外移动顺序,因为主查询不包含order_date列。

这是要求。我们应该根据搜索条件搜索客户,并根据客户的最新order_date订购客户。客户可以有多个订单,我们必须选择最新订单的order_date并对客户进行排序。

首先,我列出所有加入订单表的客户,并根据order_date订购所有记录。 一旦根据order_date对所有记录进行排序,如果客户有多个订单,则很可能会有同一客户的多次记录。

现在我在除了order_date之外应用了不同的东西,以便获得明确的客户详细信息。

谢谢, Chandu

3 个答案:

答案 0 :(得分:0)

重写查询,使其符合您的描述:您希望查看客户最后订单所订购的客户地址列表。要获取每个地址的条目,您按地址分组。并且按最后订单日期降序排序,您可以通过max(order_date)desc。

订购
SELECT 
  cc.customer_id,
  cc.email,
  cc.title,
  cc.fname,
  cc.lname, 
  cc.work_phone,
  cc.mobile_phone,
  cc.home_phone,
  cc.blacklist_reason, 
  cc.domain,
  cc.domain_group,
  cc.my_account_flag,
  cc.marketing_preference, 
  ca.city,
  ca.address1,
  ca.address2,
  ca.state, 
  ca.country,
  ca.zip,
  ca.country_code
FROM  customer cc 
INNER JOIN customer_address ca ON cc.customer_id = ca.customer_id 
LEFT OUTER JOIN order_delivery_details odd on cc.customer_id = odd.customer_id 
WHERE cc.lname = 'XXXXXX' 
AND ca.address_purpose='XXXX'   
AND (cc.domain in ( 'XXXXXX_IE' ) OR cc.domain_group in ('XXXXX', 'YYYYYY'))   
GROUP BY ca.id
order by max(odd.order_date) desc
LIMIT 0,500;

这应该更快,因为您只需告诉dbms 您想要查看的内容,并且dbms可以找到如何实现此目的的最佳方式。

答案 1 :(得分:0)

它在客户表上选择使用的索引看起来就像是lname字段,但这似乎并没有使结果缩小很多。认为你需要添加几个索引,一个覆盖lname和domain,另一个覆盖lname和domain_group。然后你可以有2个联合查询。

SELECT 
    DISTINCT dt.customer_id,
    dt.email,
    dt.title,
    dt.fname,
    dt.lname,
    dt. work_phone,
    dt.mobile_phone,
    dt.home_phone,
    dt.blacklist_reason,
    dt. domain,
    dt.domain_group,
    dt.my_account_flag,
    dt.marketing_preference,
    dt. city,
    dt.address1,
    dt.address2,
    dt.state,
    dt. country,
    dt.zip,
    dt.country_code 
    FROM (
        SELECT 
            cc.customer_id,
            cc.email,
            cc.title,
            cc.fname,
            cc.lname, 
            cc.work_phone,
            cc.mobile_phone,
            cc.home_phone,
            cc.blacklist_reason, 
            cc.domain,
            cc.domain_group,
            cc.my_account_flag,
            cc.marketing_preference, 
            ca.city,
            ca.address1,
            ca.address2,
            ca.state, 
            ca.country,
            ca.zip,
            ca.country_code,
            odd.order_date 
        FROM 
            customer cc 
        INNER JOIN customer_address ca ON cc.customer_id=ca.customer_id 
        LEFT OUTER JOIN order_delivery_details odd on cc.customer_id=odd.customer_id 
        WHERE   cc.lname = 'XXXXXX' 
        AND     ca.address_purpose='XXXX'   
        AND  cc.domain_group in  ( 'XXXXX' , 'YYYYYY' )   
        UNION
        SELECT 
            cc.customer_id,
            cc.email,
            cc.title,
            cc.fname,
            cc.lname, 
            cc.work_phone,
            cc.mobile_phone,
            cc.home_phone,
            cc.blacklist_reason, 
            cc.domain,
            cc.domain_group,
            cc.my_account_flag,
            cc.marketing_preference, 
            ca.city,
            ca.address1,
            ca.address2,
            ca.state, 
            ca.country,
            ca.zip,
            ca.country_code,
            odd.order_date 
        FROM 
            customer cc 
        INNER JOIN customer_address ca ON cc.customer_id=ca.customer_id 
        LEFT OUTER JOIN order_delivery_details odd on cc.customer_id=odd.customer_id 
        WHERE   cc.lname = 'XXXXXX' 
        AND     ca.address_purpose='XXXX'   
        AND  cc.domain in ( 'XXXXXX_IE' ) 
        ORDER BY odd.order_date desc
    ) dt 
    LIMIT 0,500;

我不确定您的原始查询是否需要内部和外部查询。 MySQL将允许您对未返回的列进行排序。但是,看起来主要问题是索引,并且您无法通过从2个联合查询返回的列来对联合查询的结果进行排序。

答案 2 :(得分:0)

您是否尝试过这样的查询:

SELECT DISTINCT
    cc.customer_id,
    cc.email,
    cc.title,
    cc.fname,
    cc.lname, 
    cc.work_phone,
    cc.mobile_phone,
    cc.home_phone,
    cc.blacklist_reason, 
    cc.domain
    cc.domain_group,
    cc.my_account_flag,
    cc.marketing_preference, 
    ca.city,
    ca.address1,
    ca.address2,
    ca.state, 
    ca.country,
    ca.zip,
    ca.country_code,
FROM 
    customer cc 
INNER JOIN customer_address ca ON cc.customer_id=ca.customer_id 
left outer join order_delivery_details odd on cc.customer_id=odd.customer_id 
WHERE
    cc.lname = 'XXXXXX' 
    AND ca.address_purpose='XXXX'   
    AND ( cc.domain in ( 'XXXXXX_IE' ) OR cc.domain_group in  ( 'XXXXX' , 'YYYYYY' ) )
ORDER BY odd.order_date DESC
LIMIT 0,500

您不需要子选择来获得您想要的东西。