您的位置:首页 > 数据库

SQL优化_高水位线导致的性能问题

2015-07-07 09:54 465 查看
今天晨会,开发人员说SIT数据库有一张表,之前查询很快就能返回结果,现在需要5分钟才能返回结果,需要协助查找原因并优化,数据库版本11.2.0.464bitforlinux,SQL语句如下:

1
select*FROMTB_XXXXawhereEDIFLAG<>'90'andEDIFLAG<>'99'andSITE_NO='C07'andrownum<=100andBONDED_AREA='1';
这是很简单的一条SQL,性能下降这么大,肯定是有问题的,问了开发人员,他们说这张表并不存在DELETE操作,那么就应该不是碎片的问题导致的。查询这张表上的索引如下:

1
INDEX_NAMECOLUMN_NAME
2
--------------------------------------------------
3
IX_08_INVC_IDINVC_ID
4
IX_TB8_ONORD_NO
5
IX_TF008IEDIF_ETR_DATE
6
IX_XXXX_EDIFLAGEDIFLAG
7
PK_IF_008ORD_ID
索引还没少建,看看SQL的执行计划和统计信息。

01
SQL>setautotraceTRACEONLY
02
SQL>setlines200pages200
03
SQL>select*FROMTB_XXXXawhereEDIFLAG<>'90'andEDIFLAG<>'99'andSITE_NO='C07'andrownum<=100andBONDED_AREA='1';
04
05
norowsselected
06
07
Elapsed:00:04:12.31
08
09
ExecutionPlan
10
----------------------------------------------------------
11
Planhashvalue:2394103272
12
13
-------------------------------------------------------------------------------
14
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
15
-------------------------------------------------------------------------------
16
|0|SELECTSTATEMENT||3|645|120K(1)|00:24:01|
17
|*1|COUNTSTOPKEY||||||
18
|*2|TABLEACCESSFULL|TB_XXXX|3|645|120K(1)|00:24:01|
19
-------------------------------------------------------------------------------
20
21
PredicateInformation(identifiedbyoperationid):
22
---------------------------------------------------
23
24
1-filter(ROWNUM<=100)
25
2-filter("EDIFLAG"<>'90'AND"SITE_NO"='C07'AND"BONDED_AREA"='1'
26
AND"EDIFLAG"<>'99')
27
28
Statistics
29
----------------------------------------------------------
30
1795recursivecalls
31
0dbblockgets
32
442185consistentgets
33
149261physicalreads
34
0redosize
35
3779bytessentviaSQL*Nettoclient
36
481bytesreceivedviaSQL*Netfromclient
37
1SQL*Netroundtripsto/fromclient
38
39sorts(memory)
39
0sorts(disk)
40
0rowsprocessed
SQL运行一次需要的物理读442185个数据块,块大小设置8K,也就是需要物理读3.4GB,外带逻辑读149261个数据块,约等于1.1GB,查看一下这个表的大小和数据量。

01
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='TB_XXXX';
02
03
BYTES/1024/1024/1024
04
--------------------
05
3.375
06
SQL>selectcount(*)fromTB_XXXX;
07
08
COUNT(*)
09
----------
10
669387
算一下平均每条记录奖金5.3MB,每条记录5M是什么概念?表中难道存在大字段?查询结果如下:

01
SQL>descTB_XXXX

02
NameNull?Type
03
-------------------------------------------------------------------------------------
04
ORD_IDNOTNULLVARCHAR2(30)
05
SITE_NOVARCHAR2(7)
06
OUTGO_CMD_DATEDATE
07
DLVER_CDVARCHAR2(3)
08
CHG_CDVARCHAR2(3)
09
ORD_LVL_CDVARCHAR2(3)
10
DLV_RQST_DATEDATE
11
RTN_IDNUMBER(12)
12
COD_YNVARCHAR2(1)
13
CUST_IDNUMBER(12)
14
INVC_RCVER_NMVARCHAR2(20)
15
INVC_TELDVARCHAR2(20)
16
INVC_HP_TELDVARCHAR2(12)
17
INVC_ZIP_NOVARCHAR2(6)
18
INVC_ADDR_LRGNVARCHAR2(30)
19
INVC_ADDR_MRGNVARCHAR2(30)
20
INVC_ADDR_SRGNVARCHAR2(30)
21
INVC_ADDR_DTLVARCHAR2(200)
22
PURCH_CANCEL_NOTICEVARCHAR2(40)
23
PRSNT_MSGVARCHAR2(60)
24
INVC_MSGVARCHAR2(200)
25
COD_RCV_AMTNOTNULLNUMBER(15,2)
26
RCPT_GBNOTNULLVARCHAR2(3)
27
RCPT_SO_IDNUMBER(7)
28
RCPT_RCVER_NMVARCHAR2(100)
29
RCPT_ADDRVARCHAR2(200)
30
IF_ETR_DATEDATE
31
IF_MDF_DATEDATE
32
IF_RESULT_DATEDATE
33
EDIFLAGVARCHAR2(2)
34
IF_RESULTSVARCHAR2(200)
35
PVC_IDNUMBER(7)
36
LOCAL_IDNUMBER(7)
37
COUTY_IDNUMBER(7)
38
MEDI_LCLSS_IDNUMBER(7)
39
CONTACT_2VARCHAR2(120)
40
ORD_AMTNUMBER(15,2)
41
BORD_IDVARCHAR2(40)
42
ORD_NOVARCHAR2(20)
43
PAY_TYPE_CDVARCHAR2(2)
44
ADDR_TNUMBER(1)
45
INCLU_VALUABLESNUMBER(1)
46
BL_ORDER_NO_OLDVARCHAR2(40)
47
CASES_IDNUMBER(11)
48
COD_FLAGVARCHAR2(2)
49
CASHNUMBER(15,2)
50
ARCHIVE_FLAGNUMBER(2)
51
CHNL_IDVARCHAR2(2)
52
BONDED_AREAVARCHAR2(8)
53
INVC_IDVARCHAR2(30)
54
ADDR_IDNUMBER(11)
55
SN_GUIDVARCHAR2(40)
所有字段加起来,一条记录也不到1KB呀,到这里就可以断定就是高水位导致的问题。由于是SIT环境,比较随意,回收下这张表的碎片,看看能回收多少空间。

1
SQL>altertableTB_XXXXmove;
2
3
Tablealtered.
4
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='TB_XXXX';
5
6
BYTES/1024/1024/1024
7
--------------------
8
.248046875
回收完碎片,这张表才250MB,碎片硬把表撑大近15倍,MOVE完之后,索引全部失效,需要rebuild。

1
SQL>selectindex_name,statusfromuser_indexeswheretable_name='TB_XXXX';
2
3
INDEX_NAMESTATUS
4
--------------------------------------
5
IX_08_INVC_IDUNUSABLE
6
IX_TB8_ONUNUSABLE
7
IX_TF008IEDUNUSABLE
8
IX_XXXX_EDIFLAGUNUSABLE
9
PK_IF_008UNUSABLE
索引重建之后,也缩小不少,不过这一堆索引这个SQL都用不上。

01
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='IX_TB8_ON';
02
03
BYTES/1024/1024/1024
04
--------------------
05
.46484375
06
SQL>alterindexIX_TB8_ONrebuild;
07
08
Indexaltered.
09
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='IX_TB8_ON';
10
11
BYTES/1024/1024/1024
12
--------------------
13
.016601563
14
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='IX_TF008IED';
15
16
BYTES/1024/1024/1024
17
--------------------
18
.25390625
19
SQL>alterindexIX_TF008IEDrebuild;
20
21
Indexaltered.
22
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='IX_TF008IED';
23
24
BYTES/1024/1024/1024
25
--------------------
26
.014648438
27
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='IX_IF008_EDIFLAG';
28
29
BYTES/1024/1024/1024
30
--------------------
31
.018554688
32
SQL>alterindexIX_IF008_EDIFLAGrebuild;
33
34
Indexaltered.
35
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='IX_IF008_EDIFLAG';
36
37
BYTES/1024/1024/1024
38
--------------------
39
.010742188
40
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='PK_IF_008';
41
42
BYTES/1024/1024/1024
43
--------------------
44
.569335938
45
SQL>alterindexPK_IF_XXXXrebuild;
46
47
Indexaltered.
48
SQL>selectbytes/1024/1024/1024fromuser_segmentswheresegment_name='PK_IF_XXXX';
49
50
BYTES/1024/1024/1024
51
--------------------
52
.014648438
回收碎片后,这个SQL运行只需要0.12秒。

1
SQL>select*FROMTB_XXXXawhereEDIFLAG<>'90'andEDIFLAG<>'99'andSITE_NO='C07'andrownum<=100andBONDED_AREA='1';
2
3
norowsselected
4
5
Elapsed:00:00:00.12
再看下执行计划和统计信息。

01
SQL>setautotracetraceonly
02
SQL>/
03
04
norowsselected
05
06
Elapsed:00:00:00.12
07
08
ExecutionPlan
09
----------------------------------------------------------
10
Planhashvalue:2394103272
11
12
-------------------------------------------------------------------------------
13
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
14
-------------------------------------------------------------------------------
15
|0|SELECTSTATEMENT||3|645|120K(1)|00:24:01|
16
|*1|COUNTSTOPKEY||||||
17
|*2|TABLEACCESSFULL|TB_XXXX|3|645|120K(1)|00:24:01|
18
-------------------------------------------------------------------------------
19
20
PredicateInformation(identifiedbyoperationid):
21
---------------------------------------------------
22
23
1-filter(ROWNUM<=100)
24
2-filter("EDIFLAG"<>'90'AND"SITE_NO"='C07'AND"BONDED_AREA"='1'
25
AND"EDIFLAG"<>'99')
26
27
Statistics
28
----------------------------------------------------------
29
0recursivecalls
30
0dbblockgets
31
32303consistentgets
32
0physicalreads
33
0redosize
34
3779bytessentviaSQL*Nettoclient
35
481bytesreceivedviaSQL*Netfromclient
36
1SQL*Netroundtripsto/fromclient
37
0sorts(memory)
38
0sorts(disk)
39
0rowsprocessed
下面在看下这张表的数据分布,看看哪个列适合建索引。

01
SQL>selectdistinctBONDED_AREAfromTB_XXXX;
02
03
BONDED_A
04
--------
05
1
06
07
SQL>selectdistinctEDIFLAGfromTB_XXXX;
08
09
ED
10
--
11
10
12
90
13
14
SQL>selectdistinctSITE_NOfromTB_XXXX;
15
16
SITE_NO
17
-------
18
C10
19
C06
20
C81
21
C99
22
C05
23
C07
24
C01
25
C03
26
C04
27
28
9rowsselected.
29
30
SQL>selectcount(SITE_NO)fromTB_XXXXwhereSITE_NO='C07';
31
32
COUNT(SITE_NO)
33
--------------
34
40674
针对这条SQL,SITE_NO列创建索引最为有效,其他列上的索引都不会被这条SQL用到。

01
SQL>createindexix_SITE_NOonTB_XXXX(SITE_NO);
02
03
Indexcreated.
04
05
SQL>setautotraceon
06
SQL>select*FROMTB_XXXXawhereEDIFLAG<>'90'andEDIFLAG<>'99'andSITE_NO='C07'andrownum<=100andBONDED_AREA='1';
07
08
norowsselected
09
10
Elapsed:00:00:00.07
11
12
ExecutionPlan
13
----------------------------------------------------------
14
Planhashvalue:272980480
15
16
-------------------------------------------------------------------------------------------
17
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
18
-------------------------------------------------------------------------------------------
19
|0|SELECTSTATEMENT||3|645|11802(1)|00:02:22|
20
|*1|COUNTSTOPKEY||||||
21
|*2|TABLEACCESSBYINDEXROWID|TB_XXXX|3|645|11802(1)|00:02:22|
22
|*3|INDEXRANGESCAN|IX_SITE_NO|41680||91(2)|00:00:02|
23
-------------------------------------------------------------------------------------------
24
25
PredicateInformation(identifiedbyoperationid):
26
---------------------------------------------------
27
28
1-filter(ROWNUM<=100)
29
2-filter("EDIFLAG"<>'90'AND"BONDED_AREA"='1'AND"EDIFLAG"<>'99')
30
3-access("SITE_NO"='C07')
31
32
Statistics
33
----------------------------------------------------------
34
0recursivecalls
35
0dbblockgets
36
22048consistentgets
37
0physicalreads
38
0redosize
39
3779bytessentviaSQL*Nettoclient
40
481bytesreceivedviaSQL*Netfromclient
41
1SQL*Netroundtripsto/fromclient
42
0sorts(memory)
43
0sorts(disk)
44
0rowsprocessed
在SITE_NO列上创建索引后,SQL运行时间下降到0.07秒。针对这条SQL,最理想的索引是在ITE_NO列和EDIFLAG列上创建BITMAP位图索引,或者创建在EDIFLAG列上做压缩的SITE_NO列和EDIFLAG列的复合索引,下面测试下效果。

下面在创建在SITE_NO列上的压缩索引,看看是否还有提升的空间。

01
SQL>dropindexIX_SITE_NO;
02
03
Indexdropped.
04
05
Elapsed:00:00:00.26
06
07
SQL>createindexIX_SITE_NOonTB_IF008(SITE_NO,EDIFLAG)compress1;
08
09
Indexcreated.
10
11
Elapsed:00:00:05.46
12
SQL>select*FROMTB_XXXXawhereEDIFLAG<>'90'andEDIFLAG<>'99'andSITE_NO='C07'andrownum<=100andBONDED_AREA='1';
13
14
norowsselected
15
16
Elapsed:00:00:00.02
17
18
ExecutionPlan
19
----------------------------------------------------------
20
Planhashvalue:272980480
21
22
-------------------------------------------------------------------------------------------
23
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
24
-------------------------------------------------------------------------------------------
25
|0|SELECTSTATEMENT||3|645|86(2)|00:00:02|
26
|*1|COUNTSTOPKEY||||||
27
|*2|TABLEACCESSBYINDEXROWID|TB_XXXX|3|645|86(2)|00:00:02|
28
|*3|INDEXRANGESCAN|IX_SITE_NO|3||85(2)|00:00:02|
29
-------------------------------------------------------------------------------------------
30
31
PredicateInformation(identifiedbyoperationid):
32
---------------------------------------------------
33
34
1-filter(ROWNUM<=100)
35
2-filter("BONDED_AREA"='1')
36
3-access("SITE_NO"='C07')
37
filter("EDIFLAG"<>'90'AND"EDIFLAG"<>'99')
38
39
Statistics
40
----------------------------------------------------------
41
353recursivecalls
42
0dbblockgets
43
160consistentgets
44
0physicalreads
45
0redosize
46
3779bytessentviaSQL*Nettoclient
47
481bytesreceivedviaSQL*Netfromclient
48
1SQL*Netroundtripsto/fromclient
49
14sorts(memory)
50
0sorts(disk)
51
0rowsprocessed
可以看到,索引压缩后各项性能指标均降低,SQL运行时间也降为0.02秒,再看看BITMAP位图索引。

01
SQL>dropindexIX_SITE_NO;
02
03
Indexdropped.
04
05
Elapsed:00:00:00.53
06
SQL>createbitmapindexix_SITE_NOonTB_XXXX(SITE_NO,EDIFLAG);
07
08
Indexcreated.
09
10
Elapsed:00:00:00.69
11
SQL>select*FROMTB_XXXXawhereEDIFLAG<>'90'andEDIFLAG<>'99'andSITE_NO='C07'andrownum<=100andBONDED_AREA='1';
12
13
norowsselected
14
15
Elapsed:00:00:00.01
16
17
ExecutionPlan
18
----------------------------------------------------------
19
Planhashvalue:25286296
20
21
--------------------------------------------------------------------------------------------
22
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
23
--------------------------------------------------------------------------------------------
24
|0|SELECTSTATEMENT||3|645|46359(1)|00:09:17|
25
|*1|COUNTSTOPKEY||||||
26
|*2|TABLEACCESSBYINDEXROWID|TB_XXXX|3|645|46359(1)|00:09:17|
27
|3|BITMAPCONVERSIONTOROWIDS||||||
28
|*4|BITMAPINDEXRANGESCAN|IX_SITE_NO|||||
29
--------------------------------------------------------------------------------------------
30
31
PredicateInformation(identifiedbyoperationid):
32
---------------------------------------------------
33
34
1-filter(ROWNUM<=100)
35
2-filter("BONDED_AREA"='1')
36
4-access("SITE_NO"='C07')
37
filter("EDIFLAG"<>'90'AND"EDIFLAG"<>'99'AND"SITE_NO"='C07')
38
39
Statistics
40
----------------------------------------------------------
41
432recursivecalls
42
0dbblockgets
43
118consistentgets
44
11physicalreads
45
0redosize
46
3779bytessentviaSQL*Nettoclient
47
481bytesreceivedviaSQL*Netfromclient
48
1SQL*Netroundtripsto/fromclient
49
14sorts(memory)
50
0sorts(disk)
51
0rowsprocessed
可是呢,这数据库是OLTP系统,位图索引DML操作锁粒度太大,并不适合使用位图索引,最终定为压缩索引。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: