不要对date类型to_char
Posted robinson1988
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不要对date类型to_char相关的知识,希望对你有一定的参考价值。
数据库环境Oracle12c
一位运维DBA学员发来SQL优化请求,他说这是一个报表,要跑7分钟,开发天天被骂,请他优化
他搞不定,把执行计划发给我,我瞄了一眼执行计划,发现有笛卡尔积,于是叫他禁止笛卡尔积
禁止笛卡尔积之后,SQL还是要跑1分多钟,SQL语句和执行计划如下:
select rownum,substr(to_char(t.ymd,'yyyymmdd'),5,2)||'月'||
substr(to_char(t.ymd,'yyyymmdd'),7,2)||'日' as ymd ,旅客发送,货物发送,装车 from (
select ymd,国铁客运量+合资客运量+地铁客运量+神华客运量 as 旅客发送,
国铁货运量+合资货运量+地铁货运量+神华货运量 as 货物发送,
国铁装车数+合资装车数+地铁装车数+神华装车数 as 装车 from (
select ymd,serial,
zb_4002 AS 国铁客运量,
xb_2003 AS 国铁货运量,
xb_1001 AS 国铁装车数,
HZB1001 AS 合资客运量,
HZB1004 AS 合资货运量,
HZB1006 AS 合资装车数,
DZB1001 AS 地铁客运量,
DZB1004 AS 地铁货运量,
DZB1006 AS 地铁装车数,
shb1001 as 神华客运量,
shb1004 as 神华货运量,
shb1006 as 神华装车数
from
jmddb a
join
(
select
x.ymd,x.jm,zb_4002,xb_2003,xb_1001,h.HZB1001,h.HZB1004,h.HZB1006,DZB1001,DZB1004,DZB1006,
s.hzb1001 as shb1001,s.hzb1004 as shb1004,s.hzb1006 as shb1006
from
zb_4ddb x,xb_2ddb y,xb_1ddb z,HZB1DDB h,DZB1DDB d,
(
select ymd as ymd,a.admcode as jm,zm,hzb1001,hzb1004,hzb1006
from jmddb a join
(select ymd,'+' as jm,zm,hzb1001,hzb1004,hzb1006 from hzbnetd where
to_char(ymd,'yyyy-mm-dd')>=(substr(to_char(add_months(to_date('2019-05-02','yyyy-mm-dd'),-12),'yyyy-mm-dd'),0,4)||'-05-01')
and to_char(ymd,'yyyy-mm-dd')<=to_char(add_months(to_date('2019-05-02','yyyy-mm-dd'),-12),'yyyy-mm-dd') )b
on a.admcode=b.jm and a.serial =19
) s
where
to_char(x.ymd,'yyyy-mm-dd')>=(substr(to_char(add_months(to_date('2019-05-02','yyyy-mm-dd'),-12),'yyyy-mm-dd'),0,4)||'-05-01')
and to_char(x.ymd,'yyyy-mm-dd')<=to_char(add_months(to_date('2019-05-02','yyyy-mm-dd'),-12),'yyyy-mm-dd')
and x.ymd=y.ymd and x.ymd=z.ymd and x.ymd=s.ymd and x.ymd=h.ymd and x.ymd=d.ymd
and x.jm=y.jm and x.jm=z.jm and x.jm=s.jm and x.jm=h.jm and x.jm=d.jm
) b
on
a.admcode=b.jm and a.serial =19) order by ymd) t
---------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:01:18.56 | 2293K| | | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:01:18.56 | 2293K| | | |
| 2 | VIEW | | 1 | 1 | 1 |00:01:18.56 | 2293K| | | |
| 3 | SORT AGGREGATE | | 1 | 1 | 1 |00:01:18.56 | 2293K| | | |
|* 4 | HASH JOIN | | 1 | 1 | 5 |00:01:18.56 | 2293K| 1797K| 1797K| 957K (0)|
| 5 | NESTED LOOPS | | 1 | 1 | 5 |00:01:18.52 | 2288K| | | |
| 6 | NESTED LOOPS | | 1 | 1 | 5 |00:01:18.41 | 2285K| | | |
| 7 | NESTED LOOPS | | 1 | 1 | 5 |00:01:18.35 | 2283K| | | |
| 8 | NESTED LOOPS | | 1 | 1 | 5 |00:01:18.35 | 2283K| | | |
| 9 | NESTED LOOPS | | 1 | 1 | 4899 |00:00:00.01 | 381 | | | |
| 10 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 14 | | | |
|* 11 | TABLE ACCESS FULL | ZD_LJ | 1 | 1 | 1 |00:00:00.01 | 7 | | | |
|* 12 | TABLE ACCESS FULL | ZD_LJ | 1 | 1 | 1 |00:00:00.01 | 7 | | | |
|* 13 | INDEX RANGE SCAN | INDEX_HZB1_002 | 1 | 46 | 4899 |00:00:00.01 | 367 | | | |
| 14 | TABLE ACCESS BY INDEX ROWID| T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 | | | |
|* 15 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 | | | |
|* 16 | INDEX RANGE SCAN | INDEX_ZB4_003 | 4899 | 1 | 5 |00:01:18.33 | 2282K| | | |
| 17 | TABLE ACCESS BY INDEX ROWID | T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 | | | |
|* 18 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 | | | |
|* 19 | INDEX RANGE SCAN | HZBNETD_UNIQUE_INDEX | 5 | 1 | 5 |00:00:00.01 | 7 | | | |
|* 20 | INDEX RANGE SCAN | INDEX_DZB1_002 | 5 | 1 | 5 |00:00:00.06 | 1824 | | | |
| 21 | TABLE ACCESS BY INDEX ROWID | T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 | | | |
|* 22 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 | | | |
|* 23 | INDEX RANGE SCAN | INDEX_XB1_001 | 5 | 1 | 5 |00:00:00.10 | 3264 | | | |
| 24 | TABLE ACCESS BY INDEX ROWID | T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 | | | |
|* 25 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 | | | |
|* 26 | TABLE ACCESS FULL | SJ_XB2 | 1 | 1391 | 7791 |00:00:00.04 | 5279 | | | |
---------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access(TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."XB2_002",'YYYY/MM/DD') AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE
"T"."ZB4_003" END =CASE "T"."XB2_003" WHEN 'ALL' THEN '+' ELSE "T"."XB2_003" END )
11 - filter(("T"."LJ_001"=19 AND "T"."LJ_002"='+'))
12 - filter(("T"."LJ_002"='+' AND "T"."LJ_001"=19))
13 - access("T"."HZB1_002"<=)
filter(CASE "T"."HZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."HZB1_003" END ='+')
15 - access("T"."KEY"='api_rptfolder_name')
16 - access("T"."ZB4_001"='D' AND "T"."ZB4_002"<=)
filter((CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END ='+' AND "T"."LJ_002"=CASE "T"."ZB4_003" WHEN 'ALL' THEN '+'
ELSE "T"."ZB4_003" END AND "T"."LJ_002"=CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END AND
TO_CHAR(TO_DATE("T"."ZB4_002",'YYYY/MM/DD'),'yyyy-mm-dd')>='2018-05-01' AND
TO_CHAR(TO_DATE("T"."ZB4_002",'YYYY/MM/DD'),'yyyy-mm-dd')<='2018-05-05' AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END
=CASE "T"."HZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."HZB1_003" END AND
TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."HZB1_002",'YYYY/MM/DD') AND "T"."ZB4_001"='D'))
18 - access("T"."KEY"='api_rptfolder_name')
19 - access("YMD"=TO_DATE("T"."ZB4_002",'YYYY/MM/DD'))
filter((TO_CHAR(INTERNAL_FUNCTION("YMD"),'yyyy-mm-dd')>='2018-05-01' AND
TO_CHAR(INTERNAL_FUNCTION("YMD"),'yyyy-mm-dd')<='2018-05-05'))
20 - access("T"."DZB1_002"<=)
filter((CASE "T"."DZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."DZB1_003" END ='+' AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE
"T"."ZB4_003" END =CASE "T"."DZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."DZB1_003" END AND
TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."DZB1_002",'YYYY/MM/DD')))
22 - access("T"."KEY"='api_rptfolder_name')
23 - access("T"."XB1_001"='D' AND "T"."XB1_002"<=)
filter((CASE "T"."XB1_003" WHEN 'ALL' THEN '+' ELSE "T"."XB1_003" END ='+' AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE
"T"."ZB4_003" END =CASE "T"."XB1_003" WHEN 'ALL' THEN '+' ELSE "T"."XB1_003" END AND
TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."XB1_002",'YYYY/MM/DD')))
25 - access("T"."KEY"='api_rptfolder_name')
26 - filter(CASE "T"."XB2_003" WHEN 'ALL' THEN '+' ELSE "T"."XB2_003" END ='+')
Note
-----
- this is an adaptive plan
从执行计划中看到性能主要耗费在id16,id16走的是索引范围扫描,各位看官请仔细看
16 - access("T"."ZB4_001"='D' AND "T"."ZB4_002"<=)
filter((CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END ='+' AND "T"."LJ_002"=CASE "T"."ZB4_003" WHEN 'ALL' THEN '+'
ELSE "T"."ZB4_003" END AND "T"."LJ_002"=CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END AND
TO_CHAR(TO_DATE("T"."ZB4_002",'YYYY/MM/DD'),'yyyy-mm-dd')>='2018-05-01' AND
TO_CHAR(TO_DATE("T"."ZB4_002",'YYYY/MM/DD'),'yyyy-mm-dd')<='2018-05-05' AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END
=CASE "T"."HZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."HZB1_003" END AND
TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."HZB1_002",'YYYY/MM/DD') AND "T"."ZB4_001"='D'))
沙雕开发对date类型的列用了to_char(),让他把SQL里面对date类型的to_char改了
select ymd,国铁客运量+合资客运量+地铁客运量+神华客运量 as 旅客发送,
国铁货运量+合资货运量+地铁货运量+神华货运量 as 货物发送,
国铁装车数+合资装车数+地铁装车数+神华装车数 as 装车 from (
select ymd,serial,
zb_4002 AS 国铁客运量,
xb_2003 AS 国铁货运量,
xb_1001 AS 国铁装车数,
HZB1001 AS 合资客运量,
HZB1004 AS 合资货运量,
HZB1006 AS 合资装车数,
DZB1001 AS 地铁客运量,
DZB1004 AS 地铁货运量,
DZB1006 AS 地铁装车数,
shb1001 as 神华客运量,
shb1004 as 神华货运量,
shb1006 as 神华装车数
from
jmddb a
join
(
select
x.ymd,x.jm,zb_4002,xb_2003,xb_1001,h.HZB1001,h.HZB1004,h.HZB1006,DZB1001,DZB1004,DZB1006,
s.hzb1001 as shb1001,s.hzb1004 as shb1004,s.hzb1006 as shb1006
from
zb_4ddb x,xb_2ddb y,xb_1ddb z,HZB1DDB h,DZB1DDB d,
(
select ymd as ymd,a.admcode as jm,zm,hzb1001,hzb1004,hzb1006
from jmddb a join
(select ymd,'+' as jm,zm,hzb1001,hzb1004,hzb1006 from hzbnetd where
ymd >=to_date('2019-05-05','yyyy-mm-dd')
and ymd <= to_date('2019-05-05','yyyy-mm-dd') )b
on a.admcode=b.jm and a.serial =19
) s
where
x.ymd >= to_date('2019-05-05','yyyy-mm-dd')
and x.ymd <= to_date('2019-05-05','yyyy-mm-dd')
and x.ymd=y.ymd and x.ymd=z.ymd and x.ymd=s.ymd and x.ymd=h.ymd and x.ymd=d.ymd
and x.jm=y.jm and x.jm=z.jm and x.jm=s.jm and x.jm=h.jm and x.jm=d.jm
) b
on
a.admcode=b.jm and a.serial =19) order by ymd;
执行计划如下:
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.09 | 7156 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.09 | 7156 |
| 2 | VIEW | | 1 | 1 | 1 |00:00:00.09 | 7156 |
| 3 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.09 | 7156 |
| 4 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.09 | 7156 |
| 5 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.07 | 6685 |
| 6 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.04 | 1406 |
| 7 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.02 | 751 |
| 8 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 383 |
| 9 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 381 |
| 10 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 14 |
|* 11 | TABLE ACCESS FULL | ZD_LJ | 1 | 1 | 1 |00:00:00.01 | 7 |
|* 12 | TABLE ACCESS FULL | ZD_LJ | 1 | 1 | 1 |00:00:00.01 | 7 |
|* 13 | INDEX RANGE SCAN | INDEX_HZB1_002 | 1 | 1 | 1 |00:00:00.01 | 367 |
| 14 | TABLE ACCESS BY INDEX ROWID| T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 15 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 |
|* 16 | INDEX RANGE SCAN | HZBNETD_UNIQUE_INDEX | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 17 | INDEX RANGE SCAN | INDEX_DZB1_002 | 1 | 1 | 1 |00:00:00.01 | 368 |
| 18 | TABLE ACCESS BY INDEX ROWID | T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 19 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 |
|* 20 | INDEX RANGE SCAN | INDEX_XB1_001 | 1 | 1 | 1 |00:00:00.02 | 655 |
| 21 | TABLE ACCESS BY INDEX ROWID | T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 22 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 |
|* 23 | TABLE ACCESS FULL | SJ_XB2 | 1 | 3 | 1 |00:00:00.03 | 5279 |
|* 24 | INDEX RANGE SCAN | INDEX_ZB4_003 | 1 | 1 | 1 |00:00:00.01 | 471 |
| 25 | TABLE ACCESS BY INDEX ROWID | T_DIC_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 26 | INDEX UNIQUE SCAN | INDEX_SYSCONFIG | 1 | 1 | 1 |00:00:00.01 | 1 |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
11 - filter(("T"."LJ_001"=19 AND "T"."LJ_002"='+'))
12 - filter(("T"."LJ_002"='+' AND "T"."LJ_001"=19))
13 - access("T"."HZB1_002"<=)
filter((CASE "T"."HZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."HZB1_003" END ='+' AND
TO_DATE("T"."HZB1_002",'YYYY/MM/DD')>=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
TO_DATE("T"."HZB1_002",'YYYY/MM/DD')<=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
15 - access("T"."KEY"='api_rptfolder_name')
16 - access("YMD"=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
17 - access("T"."DZB1_002"<=)
filter((CASE "T"."DZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."DZB1_003" END ='+' AND
TO_DATE("T"."DZB1_002",'YYYY/MM/DD')>=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
TO_DATE("T"."DZB1_002",'YYYY/MM/DD')<=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
19 - access("T"."KEY"='api_rptfolder_name')
20 - access("T"."XB1_001"='D' AND "T"."XB1_002"<=)
filter((CASE "T"."XB1_003" WHEN 'ALL' THEN '+' ELSE "T"."XB1_003" END ='+' AND
TO_DATE("T"."XB1_002",'YYYY/MM/DD')>=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
TO_DATE("T"."XB1_002",'YYYY/MM/DD')<=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
22 - access("T"."KEY"='api_rptfolder_name')
23 - filter((CASE "T"."XB2_003" WHEN 'ALL' THEN '+' ELSE "T"."XB2_003" END ='+' AND
TO_DATE("T"."XB2_002",'YYYY/MM/DD')>=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
TO_DATE("T"."XB2_002",'YYYY/MM/DD')<=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
24 - access("T"."ZB4_001"='D' AND "T"."ZB4_002"<=)
filter((CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END ='+' AND "T"."LJ_002"=CASE
"T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END AND "T"."LJ_002"=CASE "T"."ZB4_003" WHEN 'ALL' THEN
'+' ELSE "T"."ZB4_003" END AND TO_DATE("T"."ZB4_002",'YYYY/MM/DD')>=TO_DATE(' 2019-05-05 00:00:00',
'syyyy-mm-dd hh24:mi:ss') AND TO_DATE("T"."ZB4_002",'YYYY/MM/DD')<=TO_DATE(' 2019-05-05 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END =CASE "T"."XB2_003" WHEN 'ALL'
THEN '+' ELSE "T"."XB2_003" END AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE "T"."ZB4_003" END =CASE
"T"."XB1_003" WHEN 'ALL' THEN '+' ELSE "T"."XB1_003" END AND CASE "T"."ZB4_003" WHEN 'ALL' THEN '+' ELSE
"T"."ZB4_003" END =CASE "T"."HZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."HZB1_003" END AND CASE "T"."ZB4_003" WHEN
'ALL' THEN '+' ELSE "T"."ZB4_003" END =CASE "T"."DZB1_003" WHEN 'ALL' THEN '+' ELSE "T"."DZB1_003" END AND
TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."XB2_002",'YYYY/MM/DD') AND "T"."ZB4_001"='D' AND
TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."XB1_002",'YYYY/MM/DD') AND
"YMD"=TO_DATE("T"."ZB4_002",'YYYY/MM/DD') AND TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."HZB1_002",'YYYY/M
M/DD') AND TO_DATE("T"."ZB4_002",'YYYY/MM/DD')=TO_DATE("T"."DZB1_002",'YYYY/MM/DD')))
26 - access("T"."KEY"='api_rptfolder_name')
92 rows selected.
报表秒杀了
这种案例我都遇到几百个了,本来不想发博客,但是很无语啊,经常遇到对date类型的列to_char这种案例,所以必须发博客骂一骂了
各位DBA,下一次你们再看到沙雕开发对date类型的列to_char,你直接把他鸡鸡剁了就行
以上是关于不要对date类型to_char的主要内容,如果未能解决你的问题,请参考以下文章