使用UNION ALL进行SQL查询优化

时间:2015-03-24 05:51:45

标签: mysql sql query-optimization query-performance

我按照This link

的说明操作

似乎没有太大改善(仅提高了0.09秒)。还不够,我的目标是更多地优化它。

state: id,title,abbr
regions: id,title
regions_suburbs: region_id,suburb_id
suburbs: id,state_id,region_id,postcode
properties: id,title

我正在尝试在proprety.title,suburb.title,state.abbr,state.title和suburb.postcode中找到任何关键字。

查询如下 -

[Perivous]显示0到4行(总共5行,查询花了4.7122秒)

SELECT * FROM (SELECT CASE WHEN p.id IS NOT NULL THEN CONCAT('project_id|',p.id) WHEN s.id IS NOT NULL THEN CONCAT('suburb_id|',s.id) ELSE '0' END AS id,s.title As SuburbName,s.postcode,st.abbr,CONCAT(CASE WHEN p.propertyname IS NULL THEN '' ELSE CONCAT(p.propertyname,', ') END,CASE WHEN s.title IS NULL THEN'' ELSE CONCAT(UPPER(s.title), ' ') END,CASE WHEN st.abbr IS NULL THEN '' ELSE CONCAT(UPPER(st.abbr), ' ') END,CASE WHEN s.postcode IS NULL THEN '' ELSE CONCAT(s.postcode, '') END) AS SearchTerm FROM properties p LEFT OUTER JOIN suburbs s ON p.suburb_id=s.id LEFT JOIN regions_suburbs rs ON rs.suburb_id=s.id LEFT JOIN regions r ON rs.region_id=r.id LEFT JOIN state st ON st.id=s.state_id UNION ALL SELECT CASE WHEN p.id IS NOT NULL THEN CONCAT('project_id|',p.id) WHEN s.id IS NOT NULL THEN CONCAT('suburb_id|',s.id) ELSE '0' END AS id,s.title As SuburbName,s.postcode,st.abbr,CONCAT(CASE WHEN p.propertyname IS NULL THEN '' ELSE CONCAT(p.propertyname,', ') END,CASE WHEN s.title IS NULL THEN'' ELSE CONCAT(UPPER(s.title), ' ') END,CASE WHEN st.abbr IS NULL THEN '' ELSE CONCAT(UPPER(st.abbr), ' ') END,CASE WHEN s.postcode IS NULL THEN '' ELSE CONCAT(s.postcode, '') END) AS SearchTerm FROM properties p RIGHT OUTER JOIN suburbs s ON p.suburb_id=s.id LEFT JOIN regions_suburbs rs ON rs.suburb_id=s.id LEFT JOIN regions r ON rs.region_id=r.id LEFT JOIN state st ON st.id=s.state_id UNION ALL SELECT CONCAT('state_id|',id),'' As SuburbName,'' AS postcode,abbr,title AS SearchTerm FROM state) AS U WHERE 1 AND (SuburbName LIKE 'Newtown%' OR postcode='Newtown' OR LOWER(SearchTerm) LIKE LOWER('Newtown%') OR abbr LIKE 'Newtown%') ORDER BY SearchTerm ASC LIMIT 0,10

EXPLAIN RESULT

    id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    16657   Using where; Using filesort
2   DERIVED     p   ALL     NULL    NULL    NULL    NULL    3    
2   DERIVED     s   eq_ref  PRIMARY     PRIMARY     4   residential.p.suburb_id     1    
2   DERIVED     rs  ALL     NULL    NULL    NULL    NULL    383      
2   DERIVED     r   eq_ref  PRIMARY     PRIMARY     4   residential.rs.region_id    1   Using index
2   DERIVED     st  eq_ref  PRIMARY     PRIMARY     4   residential.s.state_id  1    
3   UNION   s   ALL     NULL    NULL    NULL    NULL    16640    
3   UNION   p   ALL     NULL    NULL    NULL    NULL    3    
3   UNION   rs  ALL     NULL    NULL    NULL    NULL    383      
3   UNION   r   eq_ref  PRIMARY     PRIMARY     4   residential.rs.region_id    1   Using index
3   UNION   st  eq_ref  PRIMARY     PRIMARY     4   residential.s.state_id  1    
4   UNION   state   ALL     NULL    NULL    NULL    NULL    8    
NULL    UNION RESULT    <union2,3,4>    ALL     NULL    NULL    NULL    NULL    NULL     

[现在]显示0到4行(总共5行,查询花了4.6246秒)

SELECT CASE WHEN p.id IS NOT NULL THEN CONCAT('project_id|',p.id) WHEN s.id IS NOT NULL THEN CONCAT('suburb_id|',s.id) ELSE '0' END AS id,s.title As SuburbName,s.postcode,st.abbr,CONCAT(CASE WHEN p.propertyname IS NULL THEN '' ELSE CONCAT(p.propertyname,', ') END,CASE WHEN s.title IS NULL THEN'' ELSE CONCAT(UPPER(s.title), ' ') END,CASE WHEN st.abbr IS NULL THEN '' ELSE CONCAT(UPPER(st.abbr), ' ') END,CASE WHEN s.postcode IS NULL THEN '' ELSE CONCAT(s.postcode, '') END) AS SearchTerm FROM properties p LEFT OUTER JOIN suburbs s ON p.suburb_id=s.id LEFT JOIN regions_suburbs rs ON rs.suburb_id=s.id LEFT JOIN regions r ON rs.region_id=r.id LEFT JOIN state st ON st.id=s.state_id WHERE 1 AND (s.title LIKE 'Newtown%' OR postcode='Newtown' OR LOWER(CONCAT(CASE WHEN p.propertyname IS NULL THEN '' ELSE CONCAT(p.propertyname,', ') END,CASE WHEN s.title IS NULL THEN'' ELSE CONCAT(UPPER(s.title), ' ') END,CASE WHEN st.abbr IS NULL THEN '' ELSE CONCAT(UPPER(st.abbr), ' ') END,CASE WHEN s.postcode IS NULL THEN '' ELSE CONCAT(s.postcode, '') END)) LIKE LOWER('Newtown%') OR st.abbr LIKE 'Newtown%') UNION ALL SELECT CASE WHEN p.id IS NOT NULL THEN CONCAT('project_id|',p.id) WHEN s.id IS NOT NULL THEN CONCAT('suburb_id|',s.id) ELSE '0' END AS id,s.title As SuburbName,s.postcode,st.abbr,CONCAT(CASE WHEN p.propertyname IS NULL THEN '' ELSE CONCAT(p.propertyname,', ') END,CASE WHEN s.title IS NULL THEN'' ELSE CONCAT(UPPER(s.title), ' ') END,CASE WHEN st.abbr IS NULL THEN '' ELSE CONCAT(UPPER(st.abbr), ' ') END,CASE WHEN s.postcode IS NULL THEN '' ELSE CONCAT(s.postcode, '') END) AS SearchTerm FROM properties p RIGHT OUTER JOIN suburbs s ON p.suburb_id=s.id LEFT JOIN regions_suburbs rs ON rs.suburb_id=s.id LEFT JOIN regions r ON rs.region_id=r.id LEFT JOIN state st ON st.id=s.state_id WHERE 1 AND (s.title LIKE 'Newtown%' OR postcode='Newtown' OR LOWER(CONCAT(CASE WHEN p.propertyname IS NULL THEN '' ELSE CONCAT(p.propertyname,', ') END,CASE WHEN s.title IS NULL THEN'' ELSE CONCAT(UPPER(s.title), ' ') END,CASE WHEN st.abbr IS NULL THEN '' ELSE CONCAT(UPPER(st.abbr), ' ') END,CASE WHEN s.postcode IS NULL THEN '' ELSE CONCAT(s.postcode, '') END)) LIKE LOWER('Newtown%') OR st.abbr LIKE 'Newtown%') UNION ALL SELECT CONCAT('state_id|',id),'' As SuburbName,'' AS postcode,abbr,title AS SearchTerm FROM state WHERE 1 AND title LIKE 'Newtown%' ORDER BY SearchTerm ASC LIMIT 0,10

EXPLAIN RESULT

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     p   ALL     NULL    NULL    NULL    NULL    3    
1   PRIMARY     s   eq_ref  PRIMARY     PRIMARY     4   residential.p.suburb_id     1    
1   PRIMARY     rs  ALL     NULL    NULL    NULL    NULL    383      
1   PRIMARY     r   eq_ref  PRIMARY     PRIMARY     4   residential.rs.region_id    1   Using index
1   PRIMARY     st  eq_ref  PRIMARY     PRIMARY     4   residential.s.state_id  1   Using where
2   UNION   s   ALL     title_postcode  NULL    NULL    NULL    16640    
2   UNION   p   ALL     NULL    NULL    NULL    NULL    3    
2   UNION   rs  ALL     NULL    NULL    NULL    NULL    383      
2   UNION   r   eq_ref  PRIMARY     PRIMARY     4   residential.rs.region_id    1   Using index
2   UNION   st  eq_ref  PRIMARY     PRIMARY     4   residential.s.state_id  1   Using where
3   UNION   state   range   title   title   102     NULL    1   Using where
NULL    UNION RESULT    <union1,2,3>    ALL     NULL    NULL    NULL    NULL    NULL    Using filesort

2 个答案:

答案 0 :(得分:0)

将其翻出来。而不是计算你想要的一切,然后看看&Newtown%&#39;在每个结果中,......

  1. 为每个表格搜索&#39; Newtown%&#39;的相关字段。
  2. 将步骤1中的每个SELECT加回properties(假设这是此数据集的焦点);获取只是属性的主要密钥。
  3. UNION DISTINCT步骤2中的所有SELECT。
  4. 现在加入到需要的任何表格中,并根据步骤3中的ID,进行粗略的CONCAT等产生输出。
  5. 如果您愿意在ORDER BY中使用SearchTerm以外的其他内容,则可以获得更多性能。我建议只properties.id。有了这个,您可以在第2步和第3步中进行ORDER BY,以减少从一步到另一步铲除的数量。

    OFFSET会在您UNION时出现其他问题;我们可以单独解决此问题。)

答案 1 :(得分:0)

谢谢大家的帮助。我终于找到了减缓查询速度的罪魁祸首。

我试图从我的SQL语句中逐位删除并反复运行它。最后,在删除以下两个LEFT JOIN部件后,

       LEFT JOIN regions_suburbs rs
              ON rs.suburb_id = s.id
       LEFT JOIN regions r
              ON rs.region_id = r.id

改进
Showing rows 0 - 1 (2 total, Query took 4.8538 sec)

Showing rows 0 - 1 (2 total, Query took 0.2337 sec)

为了实现这一点,我必须对数据库设计进行一些更改。最初,属性表只存储suburb_id,因为如果我们知道suburb_id,我们可以得到它的region_id和state_id。为了避免将region_suburbs和regions表连接起来,我现在正在存储state_id,region_id和suburb_id,而不是只存储一个suburb_id。在这里我们可以从查询中取出两个LEFT JOIN,它通过利用两个额外的列存储来极大地改善查询响应时间。

修改 在我选择的列上创建一些INDEX也可以改善响应时间。