那些年,我們處理過的SQL問題

資料庫頻道發表於2018-11-30

作者 | 鄭松林

轉自 | 資料和雲

微訊號 | OraNews

分析一次SQL並行執行的產生過程

1、並行引起的災禍

一大早,某網省兄弟告訴我,資料庫會話執行的SQL開啟了並行,導致負載很高,會話也高,查了半天,沒找到具體原因,也不知道該如何解決?

對於他的問題,我直接回應了:這還不清楚嗎?常見原因無非有以下兩個:

第一:物件開啟了並行(包括索引和表)

第二:SQL語句裡面使用了PARALLEL的HINTS

現場兄弟說,都查了並沒有上面的情況,聽到他的回答,我首先對他查詢的方式持懷疑態度的,沒有設定並行度,也沒有加HINTS,執行的SQL怎麼會並行執行呢?帶著這個疑問,我叫現場兄弟把查詢結果一一截圖給我,如下(文中案例都是事後補充):

那些年,我們處理過的SQL問題


看到結果後我一時也有點摸不著頭腦,怎麼回事?遇到問題我總是告訴自己要冷靜,不急。

2、層層推進,分析問題

是不是什麼引數控制了?

SQL> show parameter parallel

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

fast_start_parallel_rollback         string      LOW

parallel_adaptive_multi_user         boolean     TRUE

parallel_automatic_tuning            boolean     FALSE

parallel_degree_limit                string      CPU

parallel_degree_policy               string      MANUAL

parallel_execution_message_size      integer     16384

parallel_force_local                 boolean     FALSE

parallel_instance_group              string     

parallel_io_cap_enabled              boolean     FALSE

parallel_max_servers                 integer     320

parallel_min_percent                 integer     0

parallel_min_servers                 integer     0

parallel_min_time_threshold          string      AUTO

parallel_server                      boolean     FALSE

parallel_server_instances            integer     1

parallel_servers_target              integer     128

parallel_threads_per_cpu             integer     2

recovery_parallelism                 integer     0

沒有發現可疑引數。

至此,表面排查的結果已經解決不了這個問題了,於是我讓現場找了一條正在並行的SQL ,手動執行,並收集一個10053事件trace,看看是否能有新發現。指令碼如下 

那些年,我們處理過的SQL問題

很快現場提供了TRACE FILE檔案給我,我優先看引數列表。

這時,我發現一個可疑的引數:parallel_query_default_dop  = 16

那些年,我們處理過的SQL問題


找到mos上關於該引數的相關資訊,是一個預設並行度的引數,該引數值的演算法如下:

DEFAULT DOP = cpu_count * parallel_threads_per_cpu* cluster_database_instances

我立刻問現場同事,執行的SQL在活動會話中體現的是不是16個並行程式。現場同事答覆我,觀察到的基本就是。至此問題明朗起來了,執行的SQL使用了預設並行度執行,受引數parallel_query_default_dop控制。既然是預設的並行度,那也應該需要設定(如果不設定,預設是1)。於是我把前期的查詢驗證物件並行度是否開啟的SQL改造了下,具體如下(文中案例都是事後補充) 

那些年,我們處理過的SQL問題

那些年,我們處理過的SQL問題

 查詢結果截圖發出來,我就開心了,這裡明顯有一個設定了並行度為DEFAULT(如果我們不設定就是1)的表和索引。然後確認了他們正是正在執行的sql中的物件。

3、問題解決

既然設定了預設並行度,那麼只需要取消預設並行度即可,即執行如下SQL

--針對表

alter table table_name noparalle;

--針對索引

Alter index index_name noparallel;

於是我叫現場把物件並行度修改為1,再次執行該SQL,發現並行消失了,資料庫恢復了正常。

問題雖然解決了,但還有一個疑問沒有解開,什麼情況下會設定的並行度為DEFUALT呢?正常建立索引和表都是1。

4、如何設定並行度為default

透過實踐發現如下2種方式可以實現並行度設定為DEFAULT。

1、建立表的時候指定:

那些年,我們處理過的SQL問題

    2、建立表之後可以修改

那些年,我們處理過的SQL問題

 小結:該問題解決第一個是思路 ,第二個是基本功要紮實。

1

DB升級之後,DBLINK引起執行計劃異常分析

背景如下:某網省採集中間庫從10.2.0.4升級到11.2.0.4(備註升級不是在老的機器上面直接升級,而是在新機器上面採用安裝遷移的方式)

升級完第二天現場找到我,說以前同步檔案資料的介面功能目前都執行非常慢(資料介面同步的方式採用的DBLINK),有時甚至無法正常執行完,影響檔案資料的同步,看來已經很嚴重了。

關鍵字:DB升級從10G升級到11G
我以前遇到過相關案例,覺得可能是升級帶來的執行計劃變化引起的。於是告知現場嘗試修改最佳化器引數即optimizer_features_enable改成10.2.0.4,可以線上改,立刻生效,指令碼如下:
alter system set optimizer_features_enable='10.2.0.4' scope=both;
修改完成後,重新在執行同步檔案資料介面的任務看是否正常。
現場經過一番測試之後,問題沒有解決,看來老的經驗無法解決該問題。
好,接下來我們做了以下模擬測試:
該SQL的文字如下:

INSERT INTO EPCT.C_CUST_ADDR@EPEXDB
(CUST_ID,
CUST_ADDR,
PROVINCE_CODE,
CITY_CODE,
COUNTY_CODE,
STREET_CODE,
VILLAGE_CODE,
ROAD_CODE,
COMMUNITY_CODE,
PLATE_NO,
TYPE_CODE,
POSTALCODE,
CA_ID,
APP_NO)
SELECT A2.CUST_ID,
A2.CUST_ADDR,
A2.PROVINCE_CODE,
A2.CITY_CODE,
A2.COUNTY_CODE,
A2.STREET_CODE,
A2.VILLAGE_CODE,
A2.ROAD_CODE,
A2.COMMUNITY_CODE,
A2.PLATE_NO,
A2.TYPE_CODE,
A2.POSTALCODE,
A2.CA_ID,
''
FROM SGPM.C_CUST_ADDR A2
WHERE A2.CUST_ID=ANY
(SELECTA3.CUST_ID
FROM SGPM.C_CONS A5,
SGPM.R_CP_CONS_RELA A4,
SGPM.C_CUST A3
 WHERE A4.CONS_ID=A5.CONS_ID
 AND A4.CP_NO=:B1
 ANDA5.CUST_ID=A3.CUST_ID);
可以看到是用到DBLINK從A資料庫到B資料庫的插入語句,這個SQL發起端在A資料庫,也就是程式部署在A資料庫中,而該SQL實際執行端在B資料庫。雖然是往B資料庫插入資料,但是會派生一個查詢SQL到A資料庫取數。
針對INSERT INTO remote_table@dblink select * from local_table這種SQL執行端都會在遠端,不是本地,無法使用HINTS driving_site指定執行端。
2、然後會在A資料庫確認一下是否派生一個SQL,並且找到該SQLID
3、現場提供SQLID之後,我們可以獲取該sql執行的相關資訊: 

select *from table(dbms_xplan.display_cursor('1ar4us01aj0hu',null,'ADVANCED'));

那些年,我們處理過的SQL問題

那些年,我們處理過的SQL問題

 

紅框裡出現的字樣引起了我的注意,眼尖的DBA應該很快會發現其中的貓膩。

對的,這裡呼叫了一個內部函式。這個函式的說明如下:

The internal Oracle function SYS_OP_C2C performs conversion
from one character set to another character set C(haracterSet)2C(haracterSet).

字符集之間的轉換。OK ,看到這裡我問現場,新舊兩套B資料庫中字符集是什麼? A資料庫字符集又是什麼?

現場答覆如下:

老的B資料庫字符集是utf-8

新的B資料庫字符集是zhs16gbk

而A資料庫字符集是utf-8

這個也就說明了,遷移到新採集中間庫之後效能急劇下降的原因找到了。

那麼解決方式有如下2種方式:

第一修改字符集,保證源目標字符集一致。 

第二建立函式索引。

2

域索引導致提交報告的展開討論

域索引導致提交報錯

最近處理了一個網省的問題,現場反饋提交報錯 ,報錯如下:

COMMIT;

ERROR at line 1:

ORA-00604: error occurred at recursive SQL level 1

ORA-20000: Oracle Text error:

DRG-50610: internal error: drexdsync

DRG-50857: oracle error in drekrtd (reselect rowid row locator)

ORA-00942: table or view does not exist

ORA-06512: at "CTXSYS.SYNCRN", line 1

ORA-06512: at line 1

看到這個錯誤,我們獲取到如下資訊

1、這個是關於域索引的報錯

2、這個是遞迴SQL導致的報錯

3、這個是報表或者檢視不存在(最大可能是許可權 或者可能就是真不存在)

見到這個錯誤,首先找現場核實下許可權問題,包括操作使用者的許可權

核查結果並沒有異常。

進一步分析:

1、查詢域索引資訊

Select * from ctxsys.ctx_indexes

2、建立一個域索引會自動建立屬性為BASIC_STORAGE的四個二級表物件和一個索引物件出來

BASIC_STORAGE has the following attributes:

  i_table_clause    Parameter clause for dr$<indexname>$I table creation.

                    The I table is the index data table.

  k_table_clause    Parameter clause for dr$<indexname>$K table creation.

                    The K table is the keymap table.

  r_table_clause    Parameter clause for dr$<indexname>$R table creation.

                    The R table is the rowid table.

  n_table_clause    Parameter clause for dr$<indexname>$N table creation.

                    The N table is the negative list table.

i_index_clause Parameter clause for dr$<indexname>$X index creation.

大家可以在自己的環境中使用如下SQL查詢

Select owner,object_name,object_type,secondary,status
from dba_objects
where owner ='SGPM'
and object_name like 'DR$INDEX_NAME$%'  --INDEX_NAME修改為你實際的名稱

現場查詢結果為空,說明域索引已經不存在了,從而導致提交報錯,也就是遞迴執行域索引的SQL報錯。

問題定位到,解決問題的辦法很容易:

重建域索引即可。

我這裡給出的例子指出了域索引的實際儲存表空間位置,目的就是可控,如果不指定就是建立使用者所在預設的表空間。

begin

--建立詞法分析

--ctx_ddl.create_preference ('chinese_lexer', 'chinese_lexer');

--儲存引數

ctx_ddl.create_preference('t1_stor','BASIC_STORAGE');

ctx_ddl.set_attribute('t1_stor','I_TABLE_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','I_INDEX_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','K_TABLE_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','R_TABLE_CLAUSE','tablespace TEST');

ctx_ddl.set_attribute('t1_stor','N_TABLE_CLAUSE','tablespace TEST');

end;

--建立域索引 指定storage引數和lexer詞法分析器引數

create index idx1_t1 on t1(object_name) indextype is ctxsys.context parameters ('lexer chinese_lexer storage t1_stor');

--同步域索引資料:(該操作有風險業務低估操作)

查詢確認域索引是否需要同步

select u.username, i.idx_name
from ctxsys.dr$index i, dba_users u
where u.user_id=i.idx_owner#
and idx_id in (select pnd_cid from ctxsys.dr$pending);

exec ctx_ddl.sync_index('IDX1_T1');

--最佳化域索引資料(該操作有風險業務低估操作)

exec ctx_ddl.optimize_index ('IDX1_T1', 'full');

3

作者簡介 

 


 鄭林松,朗新科技股份有限公司資料庫技術專家,從業10多年,主要服務移動運營商客戶,電力客戶,證券客戶,製造業客戶。精通 Oracle 效能最佳化,故障診斷和處理,也擅長MySQL資料庫最佳化和故障處理。主要負責朗新公司國家電網12個網省效能最佳化和故障處理工作以及南方電網效能最佳化和故障處理工作,主導過某證券公司冷熱資料隔離和空間回收工作(總資料量100T),主持過某電網公司XTTS遷移工作;電網公司核心營銷系統歷史資料空間回收和高水位處理工作,合計回收空間15T。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31545814/viewspace-2222243/,如需轉載,請註明出處,否則將追究法律責任。

相關文章