繁体   English   中英

使用UNION ALL进行SQL查询优化

[英]SQL Query optimization with UNION ALL

我遵循了此链接中的说明

似乎并没有太大改善(仅改善了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,郊区.title,state.abbr,state.title和郊区.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

说明结果

    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

说明结果

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

把它里面翻出来。 而不是计算您想要的所有内容,然后查看每个结果块中是否都包含“ Newtown%”,...

  1. 对于每个表,搜索“ Newtown%”的相关字段。
  2. 将步骤1中的每个SELECT返回到properties (假设这是该数据集的焦点); 获取属性的主键。
  3. UNION DISTINCT步骤2中的所有选择。
  4. 现在 ,根据需要添加到所需的任何表,并进行knarly CONCAT等操作,以生成输出-基于第3步中的ID。

完成此操作后,如果您愿意在ORDER BY中使用SearchTerm以外的其他功能,则可以提高性能。 我只建议properties.id 这样,您可以在第2步和第3步中执行ORDER BY,以减少逐步挖掘的数量。

(当您拥有UNION时, OFFSET会引起另一个问题;我们可以单独解决。)

谢谢大家的帮助。 我终于找到了使查询变慢的元凶。

我试图从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)

为此,我必须对数据库的设计进行一些更改。 最初,属性表仅存储郊区_id,因为如果我们知道郊区_id,便可以获取其region_id和state_id。 为了避免向后加入region_suburbs和region表,我现在存储state_id,region_id和郊区_id,而不是仅存储一个郊区_id。 在这种情况下,我们可以从查询中删除两个LEFT JOIN,并通过利用两个值得的额外列存储来极大地缩短查询响应时间。

编辑:在我选择的列上创建一些索引也极大地改善了响应时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM