数据库环境:SQL SERVER 2005

今天看到一条SQL,返回10条数据,执行了50多S。刚好有空,就对它进行了优化,优化后1S出结果。

先看下原始SQL

  1. SELECT t1.line_no ,
  2. MAX(sat100.confrim_date) confrim_date ,
  3. sam63_lq.company_name ,
  4. sat04.c_code ,
  5. ctlm23.corr_name ,
  6. MAX(sat04.l_date_d) l_date_d ,
  7. SUM(sat05.qty_d_order) qty_d_order ,
  8. sat100.tran_no_row
  9. FROM sat100
  10. INNER JOIN sat101 ON sat100.com_id = sat101.com_id
  11. AND sat100.tran_no = sat101.tran_no
  12. AND sat100.tran_row = sat101.tran_row
  13. LEFT JOIN sat05 ON sat101.com_id = sat05.com_id
  14. AND sat101.p_g_order_no = sat05.p_g_order_no
  15. AND sat101.p_g_order_line = sat05.p_g_order_line
  16. LEFT JOIN sat04 ON sat04.com_id = sat05.com_id
  17. AND sat04.p_g_order_no = sat05.p_g_order_no
  18. LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
  19. AND sat05.item_no = ctlm22.item_no
  20. LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
  21. AND sat100.company_id = sam63_lq.company_id
  22. LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
  23. AND sat05.cx_item_no = sam60_lq.cx_item_no
  24. LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no
  25. AND sat100.company_id = sam65_lq.company_id
  26. LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
  27. AND sat05.sa_unit = ctlm17.unit
  28. LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
  29. AND sat04.c_code = salm02.client_id
  30. LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
  31. AND sat04.c_code = ctlm23.corr_id
  32. LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
  33. LEFT JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY t2.tran_no_row ) line_no ,
  34. t2.tran_no_row
  35. FROM ( SELECT DISTINCT
  36. sat100.tran_no_row
  37. FROM sat100
  38. INNER JOIN sat101 ON sat100.com_id = sat101.com_id
  39. AND sat100.tran_no = sat101.tran_no
  40. AND sat100.tran_row = sat101.tran_row
  41. LEFT JOIN sat05 ON sat101.com_id = sat05.com_id
  42. AND sat101.p_g_order_no = sat05.p_g_order_no
  43. AND sat101.p_g_order_line = sat05.p_g_order_line
  44. LEFT JOIN sat04 ON sat04.com_id = sat05.com_id
  45. AND sat04.p_g_order_no = sat05.p_g_order_no
  46. LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
  47. AND sat05.item_no = ctlm22.item_no
  48. LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
  49. AND sat100.company_id = sam63_lq.company_id
  50. LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
  51. AND sat05.cx_item_no = sam60_lq.cx_item_no
  52. LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
  53. AND sat05.sa_unit = ctlm17.unit
  54. LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
  55. AND sat04.c_code = salm02.client_id
  56. LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
  57. AND sat04.c_code = ctlm23.corr_id
  58. LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
  59. WHERE salm02.dept_id LIKE '%'
  60. AND sat100.company_id = ''
  61. AND sat100.corr_id LIKE 'A010131%'
  62. AND sat04.l_date_d >= '2015/06/01 00:00:00'
  63. AND sat04.l_date_d <= '2015/06/30 23:59:59'
  64. ) t2
  65. ) t1 ON sat100.tran_no_row = t1.tran_no_row
  66. WHERE salm02.dept_id LIKE '%'
  67. AND sat100.company_id = ''
  68. AND sat100.corr_id LIKE 'A010131%'
  69. AND sat04.l_date_d >= '2015/06/01 00:00:00'
  70. AND sat04.l_date_d <= '2015/06/30 23:59:59'
  71. GROUP BY t1.line_no ,
  72. sam63_lq.company_name ,
  73. sat04.c_code ,
  74. ctlm23.corr_name ,
  75. sat100.tran_no_row
  76. ORDER BY t1.line_no ,
  77. sat100.tran_no_row

下面,我来说下我的优化思路:

   1.检查SQL的写法是否有问题

   先看下子查询部分,发现和外部访问的表及过滤的条件都差不多,用BeyondCompare工具检查外部查询和子查询的差别,相对于外部查询,

子查询少访问了一个表sam65_lq,即少了这部分内容“LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no AND sat100.company_id

= sam65_lq.company_id”,恰巧字段veh_no和字段company_id是sam65_lq的联合主键,因此,这部分并没有影响查询的数据。

   再看下子查询,它要实现的功能就是根据不重复的tran_no_row生成一个序号,因此,可以用dense_rank()替代子查询实现相同的功能。同时,

sat04有过滤条件,因而可以将left join sat04改成inner join sat04。

   改写后的SQL如下:

  1. SELECT line_no ,
  2. MAX(confrim_date) confrim_date ,
  3. company_name ,
  4. c_code ,
  5. corr_name ,
  6. MAX(l_date_d) l_date_d ,
  7. SUM(qty_d_order) qty_d_order ,
  8. tran_no_row
  9. FROM ( SELECT DENSE_RANK() OVER ( ORDER BY sat100.tran_no_row ) AS line_no ,
  10. sat100.confrim_date ,
  11. sam63_lq.company_name ,
  12. sat04.c_code ,
  13. ctlm23.corr_name ,
  14. sat04.l_date_d ,
  15. sat05.qty_d_order ,
  16. sat100.tran_no_row
  17. FROM sat100
  18. INNER JOIN sat101 ON sat100.com_id = sat101.com_id
  19. AND sat100.tran_no = sat101.tran_no
  20. AND sat100.tran_row = sat101.tran_row
  21. LEFT JOIN sat05 ON sat101.com_id = sat05.com_id
  22. AND sat101.p_g_order_no = sat05.p_g_order_no
  23. AND sat101.p_g_order_line = sat05.p_g_order_line
  24. INNER JOIN sat04 ON sat04.com_id = sat05.com_id
  25. AND sat04.p_g_order_no = sat05.p_g_order_no
  26. LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
  27. AND sat05.item_no = ctlm22.item_no
  28. LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
  29. AND sat100.company_id = sam63_lq.company_id
  30. LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
  31. AND sat05.cx_item_no = sam60_lq.cx_item_no
  32. LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no
  33. AND sat100.company_id = sam65_lq.company_id
  34. LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
  35. AND sat05.sa_unit = ctlm17.unit
  36. LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
  37. AND sat04.c_code = salm02.client_id
  38. LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
  39. AND sat04.c_code = ctlm23.corr_id
  40. LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
  41. WHERE salm02.dept_id IS NOT NULL
  42. AND sat100.company_id = ''
  43. AND sat100.corr_id LIKE 'A010131%'
  44. AND sat04.l_date_d >= '2015/06/01 00:00:00'
  45. AND sat04.l_date_d <= '2015/06/30 23:59:59'
  46. ) t
  47. GROUP BY line_no ,
  48. company_name ,
  49. c_code ,
  50. corr_name ,
  51. tran_no_row
  52. ORDER BY line_no ,
  53. tran_no_row

   执行后,检查数据,发现和原始SQL的数据一致,说明改写的语法没有问题。但是,执行的时间没多大改观。

   2.检查是否有缺失索引

   看了下执行计划,发现在表sat100和表sat04上都走了索引扫描,在sat100表上没有针对company_id和corr_id建和组合索引,sat04表上也没有

针对l_date_d字段建的索引,而恰巧这些列的选择性都和高,适合建索引。

   建了索引后,再执行SQL,发现最快的还是要10S。不行,还得继续优化。

  3.检查执行计划,看执行计划是否合理

  

   sat05走了索引查找,它的查询开销达到88%。sat05表作为嵌套循环的内部表,外部表有5W多行记录,sat05表总共有50多W条记录,

且在sat05表上没有任何过滤条件。因此,可以判定,这里不应该走嵌套循环,应该使用哈希连接。所以,直接强制走哈希即可。

   改写优化后的完整SQL如下:

  1. SELECT line_no ,
  2. MAX(confrim_date) confrim_date ,
  3. company_name ,
  4. c_code ,
  5. corr_name ,
  6. MAX(l_date_d) l_date_d ,
  7. SUM(qty_d_order) qty_d_order ,
  8. tran_no_row
  9. FROM ( SELECT DENSE_RANK() OVER ( ORDER BY sat100.tran_no_row ) AS line_no ,
  10. sat100.confrim_date ,
  11. sam63_lq.company_name ,
  12. sat04.c_code ,
  13. ctlm23.corr_name ,
  14. sat04.l_date_d ,
  15. sat05.qty_d_order ,
  16. sat100.tran_no_row
  17. FROM sat100
  18. INNER JOIN sat101 ON sat100.com_id = sat101.com_id
  19. AND sat100.tran_no = sat101.tran_no
  20. AND sat100.tran_row = sat101.tran_row
  21. LEFT HASH JOIN sat05 ON sat101.com_id = sat05.com_id
  22. AND sat101.p_g_order_no = sat05.p_g_order_no
  23. AND sat101.p_g_order_line = sat05.p_g_order_line
  24. INNER JOIN sat04 ON sat04.com_id = sat05.com_id
  25. AND sat04.p_g_order_no = sat05.p_g_order_no
  26. LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
  27. AND sat05.item_no = ctlm22.item_no
  28. LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
  29. AND sat100.company_id = sam63_lq.company_id
  30. LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
  31. AND sat05.cx_item_no = sam60_lq.cx_item_no
  32. LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no
  33. AND sat100.company_id = sam65_lq.company_id
  34. LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
  35. AND sat05.sa_unit = ctlm17.unit
  36. LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
  37. AND sat04.c_code = salm02.client_id
  38. LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
  39. AND sat04.c_code = ctlm23.corr_id
  40. LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
  41. WHERE salm02.dept_id IS NOT NULL
  42. AND sat100.company_id = ''
  43. AND sat100.corr_id LIKE 'A010131%'
  44. AND sat04.l_date_d >= '2015/06/01 00:00:00'
  45. AND sat04.l_date_d <= '2015/06/30 23:59:59'
  46. ) t
  47. GROUP BY line_no ,
  48. company_name ,
  49. c_code ,
  50. corr_name ,
  51. tran_no_row
  52. ORDER BY line_no ,
  53. tran_no_row

dense_rank()+hash提示改写优化SQL的更多相关文章

  1. 利用查询提示优化SQL

    数据库环境:SQL SERVER 2005 我们来看一下SQL语句及对应的数据量 SELECT COUNT(*) FROM cinvout_02 a WHERE ( a.dept_id IN ( SE ...

  2. 优化sql,返回行数少情况下,NL比hash快好多

    sql如下 select t.id, t.value, tt.sort as sortno from ENGINEERING_TYPE t left join ENGINEERING_TYPE tt ...

  3. sql语句优化SQL Server

    MS   SQL   Server查询优化方法查询速度慢的原因很多,常见如下几种 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)          2.I/O吞吐量小,形成了 ...

  4. 转载 50种方法优化SQL Server数据库查询

    原文地址 http://www.cnblogs.com/zhycyq/articles/2636748.html 50种方法优化SQL Server数据库查询 查询速度慢的原因很多,常见如下几种: 1 ...

  5. [20181220]使用提示OR_EXPAND优化.txt

    [20181220]使用提示OR_EXPAND优化.txt --//链接http://www.itpub.net/thread-2107240-2-1.html,http://www.itpub.ne ...

  6. merge into优化sql(转)

    使用Merge INTO优化SQL,性能提升巨大 分类: Oracle 2017-04-13 10:55:07   说说背景:开发有个需求,需要对新加的一个字段根据特定的业务逻辑更新数据.TPS_TR ...

  7. 如何用 SQL Tuning Advisor (STA) 优化SQL语句

    在Oracle10g之前,优化SQL是个比较费力的技术活,不停的分析执行计划,加hint,分析统计信息等等.在10g中,Oracle推出了自己的SQL优化辅助工具: SQL优化器(SQL Tuning ...

  8. mysql优化SQL语句的一般步骤及常用方法

    一.优化SQL语句的一般步骤 1. 通过show status命令了解各种SQL的执行频率 mysqladmin extended-status 或: show [session|global]sta ...

  9. 利用ordered hints优化SQL

    SQL_ID  4g70n3k9bqc5v, child number 0 ------------------------------------- MERGE INTO YJBZH_GRXDFHZ ...

随机推荐

  1. 向SharePoint页面添加后台代码

    转:http://www.cnblogs.com/chenzehe/archive/2009/12/25/1631863.html 在本文中,我将跟大家一起讨论,为MOSS的页面添加服务器端代码的另一 ...

  2. C语言volatile关键字

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储 ...

  3. 网络基础(一)ARP!!!

    ARP,Address Resolution Protocol,地址解析协议,用于IP到MAC地址的映射(知道ip得到mac),实现数据的封装过程.ARP是在Ethernet以上,所以是属于网络层   ...

  4. iPhone 6出现后,如何将一份设计稿支持多个尺寸?

    http://mp.weixin.qq.com/s?__biz=MzA4NTQzNTMwOA==&mid=201174413&idx=3&sn=c3fe5b3459bac288 ...

  5. Yii框架常见问题汇总

    然用过Yii做了一个小项目了,但是过程中间解决的问题没有随手记下来,导致新项目开始后,以前碰到的问题还得在查一遍,干脆就记下来,以便不时之需. 有新的会随时更新. 1.如何显示ActiveRecord ...

  6. Classical Inheritance in JavaScript

    JavaScript is a class-free, object-oriented language, and as such, it uses prototypal inheritance in ...

  7. 改变JVM中的参数以提高Eclipse的运行速度

    首先建立评估体系,将workspace里所有的项目close掉,关闭eclipse.优化的用例就是启动eclipse,open一个项目,eclipse会自动build这个项目,保证没有感觉到明显的卡, ...

  8. 阅读STL源码剖析之list

    首先,以我之愚见,觉得有两个地方可以优化一下,不知对否,有待商榷: 1.在list的结点定义中 template<typename T> struct __list_node { type ...

  9. java读取properties

    Java读取properties文件的方法比较多,网上我最多的文章是“Java读取properties文件的六种方法”,我看了好多的文章,在读到“博客之星-熔岩”的“Java读取properties文 ...

  10. C语言之void类型及void指针 分类: C/C++ 2015-07-13 11:24 8人阅读 评论(0) 收藏

    原文网址:http://www.cnblogs.com/pengyingh/articles/2407267.html 1.概述 许多初学者对C/C 语言中的void及void指针类型不甚理解,因此在 ...