dense_rank()+hash提示改写优化SQL
数据库环境:SQL SERVER 2005
今天看到一条SQL,返回10条数据,执行了50多S。刚好有空,就对它进行了优化,优化后1S出结果。
先看下原始SQL
SELECT t1.line_no ,
MAX(sat100.confrim_date) confrim_date ,
sam63_lq.company_name ,
sat04.c_code ,
ctlm23.corr_name ,
MAX(sat04.l_date_d) l_date_d ,
SUM(sat05.qty_d_order) qty_d_order ,
sat100.tran_no_row
FROM sat100
INNER JOIN sat101 ON sat100.com_id = sat101.com_id
AND sat100.tran_no = sat101.tran_no
AND sat100.tran_row = sat101.tran_row
LEFT JOIN sat05 ON sat101.com_id = sat05.com_id
AND sat101.p_g_order_no = sat05.p_g_order_no
AND sat101.p_g_order_line = sat05.p_g_order_line
LEFT JOIN sat04 ON sat04.com_id = sat05.com_id
AND sat04.p_g_order_no = sat05.p_g_order_no
LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
AND sat05.item_no = ctlm22.item_no
LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
AND sat100.company_id = sam63_lq.company_id
LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
AND sat05.cx_item_no = sam60_lq.cx_item_no
LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no
AND sat100.company_id = sam65_lq.company_id
LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
AND sat05.sa_unit = ctlm17.unit
LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
AND sat04.c_code = salm02.client_id
LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
AND sat04.c_code = ctlm23.corr_id
LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
LEFT JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY t2.tran_no_row ) line_no ,
t2.tran_no_row
FROM ( SELECT DISTINCT
sat100.tran_no_row
FROM sat100
INNER JOIN sat101 ON sat100.com_id = sat101.com_id
AND sat100.tran_no = sat101.tran_no
AND sat100.tran_row = sat101.tran_row
LEFT JOIN sat05 ON sat101.com_id = sat05.com_id
AND sat101.p_g_order_no = sat05.p_g_order_no
AND sat101.p_g_order_line = sat05.p_g_order_line
LEFT JOIN sat04 ON sat04.com_id = sat05.com_id
AND sat04.p_g_order_no = sat05.p_g_order_no
LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
AND sat05.item_no = ctlm22.item_no
LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
AND sat100.company_id = sam63_lq.company_id
LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
AND sat05.cx_item_no = sam60_lq.cx_item_no
LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
AND sat05.sa_unit = ctlm17.unit
LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
AND sat04.c_code = salm02.client_id
LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
AND sat04.c_code = ctlm23.corr_id
LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
WHERE salm02.dept_id LIKE '%'
AND sat100.company_id = ''
AND sat100.corr_id LIKE 'A010131%'
AND sat04.l_date_d >= '2015/06/01 00:00:00'
AND sat04.l_date_d <= '2015/06/30 23:59:59'
) t2
) t1 ON sat100.tran_no_row = t1.tran_no_row
WHERE salm02.dept_id LIKE '%'
AND sat100.company_id = ''
AND sat100.corr_id LIKE 'A010131%'
AND sat04.l_date_d >= '2015/06/01 00:00:00'
AND sat04.l_date_d <= '2015/06/30 23:59:59'
GROUP BY t1.line_no ,
sam63_lq.company_name ,
sat04.c_code ,
ctlm23.corr_name ,
sat100.tran_no_row
ORDER BY t1.line_no ,
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如下:
SELECT line_no ,
MAX(confrim_date) confrim_date ,
company_name ,
c_code ,
corr_name ,
MAX(l_date_d) l_date_d ,
SUM(qty_d_order) qty_d_order ,
tran_no_row
FROM ( SELECT DENSE_RANK() OVER ( ORDER BY sat100.tran_no_row ) AS line_no ,
sat100.confrim_date ,
sam63_lq.company_name ,
sat04.c_code ,
ctlm23.corr_name ,
sat04.l_date_d ,
sat05.qty_d_order ,
sat100.tran_no_row
FROM sat100
INNER JOIN sat101 ON sat100.com_id = sat101.com_id
AND sat100.tran_no = sat101.tran_no
AND sat100.tran_row = sat101.tran_row
LEFT JOIN sat05 ON sat101.com_id = sat05.com_id
AND sat101.p_g_order_no = sat05.p_g_order_no
AND sat101.p_g_order_line = sat05.p_g_order_line
INNER JOIN sat04 ON sat04.com_id = sat05.com_id
AND sat04.p_g_order_no = sat05.p_g_order_no
LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
AND sat05.item_no = ctlm22.item_no
LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
AND sat100.company_id = sam63_lq.company_id
LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
AND sat05.cx_item_no = sam60_lq.cx_item_no
LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no
AND sat100.company_id = sam65_lq.company_id
LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
AND sat05.sa_unit = ctlm17.unit
LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
AND sat04.c_code = salm02.client_id
LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
AND sat04.c_code = ctlm23.corr_id
LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
WHERE salm02.dept_id IS NOT NULL
AND sat100.company_id = ''
AND sat100.corr_id LIKE 'A010131%'
AND sat04.l_date_d >= '2015/06/01 00:00:00'
AND sat04.l_date_d <= '2015/06/30 23:59:59'
) t
GROUP BY line_no ,
company_name ,
c_code ,
corr_name ,
tran_no_row
ORDER BY line_no ,
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如下:
SELECT line_no ,
MAX(confrim_date) confrim_date ,
company_name ,
c_code ,
corr_name ,
MAX(l_date_d) l_date_d ,
SUM(qty_d_order) qty_d_order ,
tran_no_row
FROM ( SELECT DENSE_RANK() OVER ( ORDER BY sat100.tran_no_row ) AS line_no ,
sat100.confrim_date ,
sam63_lq.company_name ,
sat04.c_code ,
ctlm23.corr_name ,
sat04.l_date_d ,
sat05.qty_d_order ,
sat100.tran_no_row
FROM sat100
INNER JOIN sat101 ON sat100.com_id = sat101.com_id
AND sat100.tran_no = sat101.tran_no
AND sat100.tran_row = sat101.tran_row
LEFT HASH JOIN sat05 ON sat101.com_id = sat05.com_id
AND sat101.p_g_order_no = sat05.p_g_order_no
AND sat101.p_g_order_line = sat05.p_g_order_line
INNER JOIN sat04 ON sat04.com_id = sat05.com_id
AND sat04.p_g_order_no = sat05.p_g_order_no
LEFT JOIN ctlm22 ON sat05.com_id = ctlm22.com_id
AND sat05.item_no = ctlm22.item_no
LEFT JOIN sam63_lq ON sat100.com_id = sam63_lq.com_id
AND sat100.company_id = sam63_lq.company_id
LEFT JOIN sam60_lq ON sat05.com_id = sam60_lq.com_id
AND sat05.cx_item_no = sam60_lq.cx_item_no
LEFT JOIN sam65_lq ON sat100.car_no = sam65_lq.veh_no
AND sat100.company_id = sam65_lq.company_id
LEFT JOIN ctlm17 ON sat05.com_id = ctlm17.com_id
AND sat05.sa_unit = ctlm17.unit
LEFT JOIN salm02 ON sat04.com_id = salm02.com_id
AND sat04.c_code = salm02.client_id
LEFT JOIN ctlm23 ON sat04.com_id = ctlm23.com_id
AND sat04.c_code = ctlm23.corr_id
LEFT JOIN ctlm08 ON salm02.dept_id = ctlm08.dept_id
WHERE salm02.dept_id IS NOT NULL
AND sat100.company_id = ''
AND sat100.corr_id LIKE 'A010131%'
AND sat04.l_date_d >= '2015/06/01 00:00:00'
AND sat04.l_date_d <= '2015/06/30 23:59:59'
) t
GROUP BY line_no ,
company_name ,
c_code ,
corr_name ,
tran_no_row
ORDER BY line_no ,
tran_no_row
dense_rank()+hash提示改写优化SQL的更多相关文章
- 利用查询提示优化SQL
数据库环境:SQL SERVER 2005 我们来看一下SQL语句及对应的数据量 SELECT COUNT(*) FROM cinvout_02 a WHERE ( a.dept_id IN ( SE ...
- 优化sql,返回行数少情况下,NL比hash快好多
sql如下 select t.id, t.value, tt.sort as sortno from ENGINEERING_TYPE t left join ENGINEERING_TYPE tt ...
- sql语句优化SQL Server
MS SQL Server查询优化方法查询速度慢的原因很多,常见如下几种 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了 ...
- 转载 50种方法优化SQL Server数据库查询
原文地址 http://www.cnblogs.com/zhycyq/articles/2636748.html 50种方法优化SQL Server数据库查询 查询速度慢的原因很多,常见如下几种: 1 ...
- [20181220]使用提示OR_EXPAND优化.txt
[20181220]使用提示OR_EXPAND优化.txt --//链接http://www.itpub.net/thread-2107240-2-1.html,http://www.itpub.ne ...
- merge into优化sql(转)
使用Merge INTO优化SQL,性能提升巨大 分类: Oracle 2017-04-13 10:55:07 说说背景:开发有个需求,需要对新加的一个字段根据特定的业务逻辑更新数据.TPS_TR ...
- 如何用 SQL Tuning Advisor (STA) 优化SQL语句
在Oracle10g之前,优化SQL是个比较费力的技术活,不停的分析执行计划,加hint,分析统计信息等等.在10g中,Oracle推出了自己的SQL优化辅助工具: SQL优化器(SQL Tuning ...
- mysql优化SQL语句的一般步骤及常用方法
一.优化SQL语句的一般步骤 1. 通过show status命令了解各种SQL的执行频率 mysqladmin extended-status 或: show [session|global]sta ...
- 利用ordered hints优化SQL
SQL_ID 4g70n3k9bqc5v, child number 0 ------------------------------------- MERGE INTO YJBZH_GRXDFHZ ...
随机推荐
- Android4.0 -- UI控件之 Menu 菜单的的使用(二)
上一讲我们讲解了android中在代码或者xml文件中定义菜单,这一讲我们继续来讲解一下定义菜单的其他方式:创建上下文的菜单.查看API文档 Menus :Creating Contextual Me ...
- MFC DialogBar 按钮灰色不响应
在MFC单文档加添加DialogBar,然后在DialogBar上添加按钮,会出现如下情况,单击无响应. 解决方案: 在 CSideDialogBar头文件和CPP文件里添加如下函数 afx_msg ...
- Android SeekBar 和 draw9patch 的使用
今天要使用一个SeekBar控件,其实我觉得Android默认样式已经很不错了,无奈设计不同意,而且SeekBar左右两边也有图片,默认样式和图片也确实不协调,因此这里使用图片自定义SeekBar样式 ...
- DS1302-演示代码
参考DS1302数据手册,尽管数据手册是英文,但是很有帮助,再结合网上众多的代码写出了下面这个例子,除了涓流充电(trickle charger)功能没使用外,内部的RAM和寄存器功能都使用到了,包括 ...
- JAVA网络编程基础知识
网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协 ...
- html自定义checkbox、radio、select —— checkbox、radio篇
前些日子,所在公司项目的UI做了大改,前端全部改用 Bootstrap 框架,Bootstrap的优缺点在此就不详述了,网上一大堆相关资料. 前端的设计就交给我和另一个同事[LV,大学同班同学,毕业后 ...
- mongDB基本命令和Java操作MongoDB
上一篇博文<mongoDB安装>我们安装了mongoDB,现在来复习一下它的一些基本命令:mongoDB的bin目录加入到path之后,命令行中输入mongo: 然后我们进入正题 1.查看 ...
- 【转】shell 教程——07 Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数
前面已经讲到,变量名只能包含数字.字母和下划线,因为某些包含其他字符的变量有特殊含义,这样的变量被称为特殊变量. 例如,$ 表示当前Shell进程的ID,即pid,看下面的代码: $echo $$ 运 ...
- Command-line interface
A command-line interface (CLI), also known as command-line user interface, console user interface, a ...
- Lattice Diamond安装
1.下载:到Lattice官网 http://www.latticesemi.com/ 注册一个lattice的账号后就可以去下载Diamond,登陆后如下图,根据自己系统情况选择对应的版本,我用的是 ...