调优 SQL 语句性能

Posted

技术标签:

【中文标题】调优 SQL 语句性能【英文标题】:Tuning SQL statement performance 【发布时间】:2015-07-31 07:48:40 【问题描述】:

我有两个返回相同结果的查询:

1.

SELECT DISTINCT 
         cvc.object_id
        , cvc.object_name  
 FROM ems.ibo_sm_cvc_rfs cvc,  
      ems.ibo_alcatel_mse_locale poi, 
      ems.ibo_nbn_csa csa, 
      ems.ibo_sm_ean_service_sites_rfs sites, 
      ems.ibo_sm_ean_service_site_rfs site  
WHERE poi.object_name ='testPoi'  
  AND csa.parent_id = poi.object_id  
  AND cvc.csa_id = csa.csa_id  
  AND sites.parent_id = cvc.object_id  
  AND site.service_site_type = 'testSite'  
  AND site.object_name IN (SELECT mse_chassis.object_name  
                             FROM ems.ibo_alcatel_mse_chassis mse_chassis  
                            WHERE mse_chassis.parent_id = poi.object_id);

2。 :

SELECT cvc.object_id,
       cvc.object_name
  FROM ems.ibo_sm_cvc_rfs cvc
  JOIN ems.ibo_nbn_csa csa
    ON cvc.csa_id = csa.csa_id
  JOIN ems.ibo_sm_ean_service_sites_rfs sites
    ON sites.parent_id   = cvc.object_id
 WHERE csa.parent_id IN (SELECT poi.object_id
                           FROM ems.ibo_alcatel_mse_locale poi
                          WHERE poi.object_id IN (SELECT csa.parent_id FROM ems.ibo_nbn_csa csa)
                             AND poi.object_name = 'testPoi'
                             AND poi.object_id  IN 
                                 (SELECT mse_chassis.parent_id
                                    FROM EMS.ibo_alcatel_mse_chassis mse_chassis
                                   WHERE mse_chassis.object_name IN
                                         (SELECT site.object_name
                                            FROM EMS.ibo_sm_ean_service_site_rfs site
                                           WHERE site.service_site_type = 'testSite')
                                 )
                         );

对我来说奇怪的是,第一个语句在 0.156 秒内完成,而第二个语句在 0.624 秒内完成。需要提一下,所有 ems.* 对象都是视图,我发现基本上 where 子句中的每一列都被索引了。 如果需要,我可以放置视图架构,但我宁愿不要,因为是公司信息。也许一双经验的眼睛可能会看到这两种说法的改进

【问题讨论】:

发布两个查询的执行计划 您的第二个查询中有很多子查询,所以它会变慢也就不足为奇了。 eeek,不解释计划图像,几乎没用恕我直言 这不仅仅是子查询的数量,每个子查询都是通过 IN ( subquery ) 使用的,而 IN 的性能可能很糟糕。 AFAIK oracle 在幕后应该将 IN 转换为 JOIN,但我猜它被 IN ..WHERE .. IN 弄糊涂了 【参考方案1】:

正如@Mihai 指出的那样,您的第二个查询充满了子查询,我会再进一步​​微调您发布的第一个查询,如下所示

SELECT DISTINCT 
    cvc.object_id
    , cvc.object_name  
FROM ems.ibo_sm_cvc_rfs cvc 
    JOIN ems.ibo_nbn_csa csa ON cvc.csa_id = csa.csa_id
    JOIN ems.ibo_alcatel_mse_locale poi ON csa.parent_id = poi.object_id 
    JOIN ems.ibo_sm_ean_service_sites_rfs sites ON sites.parent_id = cvc.object_id 
    JOIN EMS.ibo_alcatel_mse_chassis mse_chassis ON mse_chassis.parent_id = poi.object_id
    JOIN EMS.ibo_sm_ean_service_site_rfs site ON site.object_name = mse_chassis.object_name
WHERE poi.object_name ='testPoi' 
AND site.service_site_type = 'testSite';

注意两点:

    我已将您的隐式连接语法修改为显式连接语法

    我已将您的最后一个带有IN 子句的子查询修改为JOIN 语句

【讨论】:

我认为这是最好的方法,我关心的是消除Distinct带来的开销 如果您在答案中运行发布的查询,它会获取什么时间范围?是否超过0.156秒【参考方案2】:
SELECT 
    cvc.object_id
    , cvc.object_name  
FROM ems.ibo_sm_cvc_rfs cvc,  
    ems.ibo_alcatel_mse_locale poi, 
    ems.ibo_nbn_csa csa, 
    ems.ibo_sm_ean_service_sites_rfs sites, 
    EMS.ibo_sm_ean_service_site_rfs site,
    EMS.ibo_alcatel_mse_chassis mse_chassis  
WHERE poi.object_name ='testPoi'  
    AND csa.parent_id = poi.object_id  
    AND cvc.csa_id = csa.csa_id  
    AND sites.parent_id = cvc.object_id  
    AND site.service_site_type = 'testSite'  
    AND site.object_name = mse_chassis.object_name  
    AND mse_chassis.parent_id = poi.object_id 
GROUP BY cvc.object_id, cvc.object_name 

旨在进行非常有效的松散索引扫描,因此添加此索引

CREATE INDEX objects_idx
  ON ibo_sm_cvc_rfs (object_id, object_name);

【讨论】:

需要与 dba 核对,然后看看创建额外索引会有什么影响

以上是关于调优 SQL 语句性能的主要内容,如果未能解决你的问题,请参考以下文章

sql server 性能调优之 SQL语句阻塞查询

Db2 数据库 SQL 语句性能调优 8 个技巧

性能调优篇 - TPS低 - 优化SQL语句

SQL 语句性能调优

SQL语句调优

MySQL性能调优(软调优)