【问题标题】:Very slow SQL query with only two left joins非常慢的 SQL 查询,只有两个左连接
【发布时间】:2016-09-05 04:29:47
【问题描述】:

我正在使用左连接加入三个表“客户”、“客户地址”和“国家”,因为我允许客户拥有一个或没有地址。 目前我有 13k 多个客户,查询大约需要 40 秒。我尝试了内部加入,但在这种情况下,我没有得到没有地址的客户。 'ON' 中的所有列都已编入索引,但差别不大。 这是我的查询:

SELECT DISTINCT *, 
CASE
  WHEN customer_address.customerid is NULL THEN customer.customerid
  ELSE customer_address.customerid
  END as customerid, 
CASE
  WHEN address1 = '' THEN 'NA'
  ELSE address1
  END as address1 
FROM customer 
LEFT JOIN customer_address ON customer.customerid = customer_address.customerid 
LEFT JOIN country ON country.id = customer_address.country 
WHERE deleted='0'  
ORDER BY customer.customerid 
DESC 
LIMIT 0, 10

任何帮助将不胜感激

编辑:

下面是对三个表的“解释”:

客户

Field        Type          Null Key  Default  Extra 
customerid   int(12)       NO   PRI  NULL     auto_increment
forename     varchar(128)  YES       NULL    
surname      varchar(128)  YES       NULL    
company      varchar(64)   YES       NULL    
tel          varchar(32)   YES       NULL    
tel2         varchar(32)   YES       NULL    
fax          varchar(32)   YES       NULL    
mob          varchar(32)   YES       NULL    
email        varchar(255)  YES       NULL    
date_reg     date          YES       NULL    
last_update  datetime      YES       NULL    
deleted      int           NO     

客户地址

Field        Type          Null Key  Default     Extra 
addressid    varchar(12)   NO   PRI         
customerid   varchar(12)   YES  MUL  NULL    
address1     varchar(128)  YES       NULL    
address2     varchar(128)  YES       NULL    
town         varchar(128)  YES       NULL    
county       varchar(128)  YES  MUL  NULL    
postcode     varchar(12)   YES       NULL    
country      int(12)       YES       NULL    
address_date datetime      YES       NULL    
isprimary    int           NO   not     

国家

Field        Type          Null Key  Default     Extra     
id           int(12)       NO   PRI  0     
country      varchar(255)  YES       NULL

目前没有删除!='0'

编辑 2:

查询说明:

id select_type  table             partitions  type    possible_keys  key      key_len  ref                               rows   filtered   Extra     
1  SIMPLE       customer          NULL        ALL     deleted        NULL     NULL     NULL                             13082   99.98      Using where; Using temporary; Using filesort
1  SIMPLE       customer_address  NULL        ALL     NULL           NULL     NULL     NULL                              9983   100.00     Using where; Using join buffer (Block Nested Loop)
1  SIMPLE       country           NULL        eq_ref  PRIMARY,id     PRIMARY  4        db_name.customer_address.country     1   100.00     NULL

编辑 3:

1   SIMPLE  customer    NULL    index   NULL    customerid  4   NULL    1   10.00   Using where; Using temporary
1   SIMPLE  customer_address    NULL    ALL     NULL    NULL    NULL    NULL    9983    100.00  Using where
1   SIMPLE  country     NULL    eq_ref  PRIMARY,id  PRIMARY     4   db_name.customer_address.country    1   100.00  NULL

【问题讨论】:

  • 我们在deleted 列上有索引吗?
  • 真的有必要吗?删除它们,看看需要多长时间
  • 不使用 Distinct,不使用 Case-Then-Else 的...的性能如何?
  • 能否请您添加explain plancreate table 以及删除了多少行=0?
  • 您能否为查询添加解释?

标签: mysql sql


【解决方案1】:

好吧,您必须输入不使用任何索引的所有类型的查询。其中一个甚至有可怕的文件排序,这是一项非常昂贵的操作。

  1. 在 customer_address.customerid 字段上添加索引。这将用于将 customer_address 表中的记录与主客户表进行匹配。

  2. 列出要从查询中返回的列,不要使用 *.例如,我不明白为什么需要同时从客户表和地址表中返回 customerid。

  3. 去掉第一个 case 语句。 customer.customerid 字段将始终被填充。

  4. 在customer表后添加索引提示,让mysql考虑使用customerid索引进行排序:

    ... FROM customer FORCE INDEX index_name_forcustomerid_field ...

  5. 您可能需要考虑增加join_buffer_size 服务器变量,但是,首先添加索引应该会有很大帮助。

【讨论】:

  • 好点,但对我来说没有任何帮助。我发现 ORDER BY 导致了问题。任何建议如何解决这个问题?谢谢
  • 这就是力指数所要解决的问题。显然,mysql 并不那么容易被说服使用索引进行排序。可能是因为您要返回客户表中的所有行和列。
  • 是的,但对我来说没有帮助。感谢您的尝试!
  • 您能否在对查询进行更改后更新您的说明?我想看看它是如何改变执行计划的。
  • 在 EDIT 3 下更新了它。谢谢
【解决方案2】:

你可以试试这个。您不需要使用第一个 CASE 语句,因为您永远不会将 CustomerId 接收为 NULL。我也删除了 ORDER BY 子句,因为我假设它会提高查询性能(CustomerId 是一个主键,它显示了记录在数据库中的物理排列方式。默认排列顺序是升序。)

    SELECT DISTINCT *, C.customerid as customerid, 
CASE
      WHEN customer_address.address1 = '' THEN 'NA'
      ELSE customer_address.address1
      END as address1 from (select * 
    FROM customer where deleted='0' order by customerid DESC) AS C  
    LEFT JOIN customer_address ON C.customerid = customer_address.customerid 
    LEFT JOIN country ON country.id = customer_address.country 
    LIMIT 0, 10

【讨论】:

  • 这样表现更好,这就是我设法定位问题所在的方法。基本上 ORDER BY 会减慢它的速度。如果我把它从我的身上取下来,它会下降到 0.02 秒。任何建议
猜你喜欢
  • 2010-12-07
  • 1970-01-01
  • 2020-02-04
  • 1970-01-01
  • 2015-04-19
  • 2012-10-23
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
相关资源
最近更新 更多