【问题标题】:SQL Query optimization with UNION ALL使用 UNION ALL 优化 SQL 查询
【发布时间】:2015-03-24 05:51:44
【问题描述】:

我按照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

解释结果

    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

【问题讨论】:

  • 显示explain的查询结果。 explain select ...
  • 请提供数据库结构(图表)并说明您要做什么,以便我们任何人都可以为您提供优化的解决方案。因为有时你必须做更多的查询,但它的结果比一个大查询要早得多
  • 已添加表结构、查询目的和Expalin结果。
  • 嗯,部分表结构... ID 是 Properties 表的 PK 吗?在什么情况下它可以为 NULL(除了 RIGHT JOIN 的结果)?我可以安全地推断出某些房产与郊区无关吗?

标签: mysql sql query-optimization query-performance


【解决方案1】:

把它翻过来。而不是计算您想要的所有内容,然后查看“Newtown%”是否在每个结果片段中,...

  1. 对于每个,在相关字段中搜索“Newtown%”。
  2. 将步骤 1 中的每个 SELECT 加入到properties(假设这是该数据集的焦点); 只需属性的 PRIMARY KEY。
  3. UNION DISTINCT 步骤 2 中的所有 SELECT。
  4. 现在加入任何需要的表,并根据第 3 步中的 id 执行 knarly CONCAT 等以产生输出。

完成此操作后,如果您愿意在 ORDER BY 中使用 SearchTerm 以外的其他内容,则可以获得更多性能。我建议只是properties.id。这样,您可以在第 2 步和第 3 步中执行 ORDER BY,以减少一步一步铲除的数量。

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

【讨论】:

    【解决方案2】:

    在这里感谢大家的帮助。我终于找到了导致查询速度变慢的罪魁祸首。

    我试图从我的 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。为了避免重新加入regions_suburbs 和regions 表,我现在存储state_id、region_id 和suburb_id 而不是只存储一个suburb_id。在这种情况下,我们可以从查询中取出两个 LEFT JOIN,它通过利用两个额外的列存储来极大地提高查询响应时间,这是值得的。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多