SQL語句執行卡住問題部分排查思路
平時正常執行的SQL,某個時刻執行了很長時間仍未返回結果。通常有以下幾種情況:
1)SQL語句執行可能涉及到不同粒度級別的鎖申請和對象鎖定,也就是說不同的SQL語句執行時,如果訪問相同對象可能會沖突,需要先排查鎖沖突情況,SQL被哪些會話阻塞了,,表現為有阻塞會話(pid大于0);
2)SQL語句可能被2pc兩階段事務阻塞,表現為阻塞會話pid=0;
3)SQL語句可能被同步事務阻塞,在配置了同步備機,但同步備機有異常或延遲的情況,表現為會話等待事件類型為SyncRep;
4)SQL語句沒有被阻塞,可能因統計信息不準確而生成了差的執行計劃,執行時間太長。
TeleDB分布式架構,在CN節點上顯示為運行中的SQL,可能會在某個DN節點上執行被阻塞,所以需要檢查每個DN節點該SQL的執行情況。
SQL語句被其它SQL語句阻塞問題
問題描述
平時正常執行的SQL,執行了很長時間仍未返回結果,通過pg_blocking_pids(pid)得到有阻塞的會話pid,且pid大于0。
每個CN、DN主節點上執行以下SQL,檢查是否有會話阻塞:
select pid,pg_blocking_pids(pid),EXTRACT(EPOCH FROM (now()-query_start)),
wait_event_type,wait_event,query
from pg_stat_activity
where wait_event_type ='Lock' and pid!=pg_backend_pid();
返回如下示例內容,pg_blocking_pids 返回非0,則表示該進程阻塞了當前SQL;
pid | pg_blocking_pids | date_part | wait_event_type | wait_event | query
------+------------------+-----------+-----------------+---------------+---------------------------------------
1302 | {11582} | 102.134252 | Lock | transactionid | INSERT INTO test (id, c1) VALUES
(1, 1)
(1 row)
可能影響
SQL執行時間很長未返回結果,導致相關業務受影響。
解決步驟
- 執行以下SQL,進一步檢查阻塞會話ID對應的SQL語句,是否被其它會話阻塞;
select pid,pg_blocking_pids(pid),EXTRACT(EPOCH FROM (now()-query_start)),
wait_event_type,wait_event,query,query
from pg_stat_activity
where pid=11582;
- 與業務側確認,阻塞的會話是否可以停掉;如果可以停掉,執行以下SQL停掉阻塞的會話:
取消會話,執行以下SQL,可能不成功,其中xxx為需要停掉的SQL會話的PID:
select pg_cancel_backend(xxx);
如果取消會話不成功,執行以下SQL,其中xxx為需要停掉的SQL會話的PID:
select pg_terminate_backend(xxx);
- 常見的SQL阻塞場景:執行DDL語句,例如TRUNCATE TABLE清空表、ALTER TABLE修改表結構,會申請獨占鎖,如果有會話在訪問這個表,那么DDL語句就會被阻塞,等待這個表上的會話結束;后續這個表上的SELECT語句又會被DDL語句阻塞;造成更大面積的阻塞。
針對此類場景,有如下建議:
1)DDL語句屬于表結構變更語句,生產環境中不應隨意執行,需要申請維護窗口;
2)在執行DDL語句前,可以先檢查該該表上是否有會話,在允許的前提下先清理會話,再執行DDL語句;
3)所有DDL語句執行產,建議會話級設置lock_timeout參數,在一段時間內如果沒有申請到鎖就退出,避免造成大面積SQL阻塞;例如 set lock_timeout='10s',那么DDL語句如果10秒沒有獲取到獨占鎖,就會退出。
SQL語句被2pc事務阻塞問題
問題描述
在配置了同步備機,同步備機有異常或延遲的情況下,SQL語句被同步事務阻塞,表現為阻塞會話pid=0;
每個CN、D主節點上執行以下SQL,檢查是否為同步復制:
select pid,pg_blocking_pids(pid),EXTRACT(EPOCH FROM (now()-query_start)),
wait_event_type,wait_event,query
from pg_stat_activity
where wait_event_type ='Lock' and pid!=pg_backend_pid();
返回以下如內容,pg_blocking_pids=0,則說明被2pc事務阻塞。
datname | pid | pg_blocking_pids | date_part | wait_event_type | wait_event | query
----------+-------+------------------+-------------+-----------------+---------------+----------------
teledb | 31742 | {0} | 1385.124791 | Lock | transactionid | Remote Subplan
(1 row)
可能影響
發現SQL長時間被2pc事務阻塞,說明有2pc殘留,需要及時處理,否則會導致相關SQL持續被阻塞。
解決步驟
參考2pc殘留類問題處理,清理2pc殘留。
SQL語句被同步事務阻塞問題
問題描述
在配置了同步備機,同步備機有異常或延遲的情況下,SQL語句被同步事務阻塞,表現為會話等待事件類型為SyncRep;
每個CN、D主節點上執行以下SQL,檢查是否為同步復制:
teledb=# select current_setting('synchronous_commit') as synchronous_commit,
current_setting('synchronous_standby_names') as synchronous_standby_names,
array((select sync_state from pg_stat_replication)) as sync_state;
synchronous_commit | synchronous_standby_names | sync_state
--------------------+------------------------------+------------
on | FIRST 1 (172.16.16.16:11300) | {sync}
(1 row)
如果返回值為synchronous_commit = on、synchronous_standby_names 不為空則表示主備為同步復制模式,此時sync_state 值必需為 sync,否則無法執行 ddl 或者更新的 dml 操作。
每個CN、D主節點上執行以下SQL,檢查是否有同步復制等待:
select query,wait_event_type,wait_event,EXTRACT(EPOCH FROM (now()-query_start)) from
pg_stat_activity where wait_event='SyncRep';
如果返回有wait_event='SyncRep'的記錄,說明SQL在等待同步復制備機響應。
可能影響
同步復制備機異常或延遲,導致DDL、DML、COMMIT語句等待處理等待狀態。
解決步驟
- 檢查同步復制備機狀態,嘗試修復;
- 如果不能快速修復,在與業務側溝通取得確認后,可暫時將同步復制模式更為異步復制;
修改為異步方法參考:修改主節點配置文件postgresql.conf.user 中以下參數:
synchronous_commit =local
synchronous_standby_names=''
配置文件修改完成后,執行select pg_reload_conf();重新加載配置;
- 修復同步復制備機,恢復同步復制模式。
SQL語句執行慢的問題
問題描述
平時正常執行的SQL,某個時刻執行了很長時間仍未返回結果,但未找到阻塞的會話,也沒有同步事務阻塞,正常執行中,僅是執行慢。
可能因統計信息不準確而生成了差的執行計劃,執行時間太長。
可能影響
平時正常執行的SQL,某個時刻執行了很長時間仍未返回結果,導致相應業務受影響。
解決方案
- 手動執行explain SQL查看執行計劃,確認執行計劃是否符合預期;
- 有條件的情況,可以執行explain (analyze,verbose,buffers) SQL查看實際執行計劃,找到具體慢的位置,并進行相應優化;
- 對于應用調用SQL使用綁定變量的情況,需要核實傳入的變量類型與字段類型是否匹配,是否有隱式類型轉換導致分布鍵、索引失效;
- 是否有truncate+insert等大批量數據變更,導致統計信息不準確;可以嘗試手動收集該表的統計信息,然后再執行SQL語句;
- 借助一些插件,觀察應用調用的SQL語句執行過程中的執行計劃,驗證執行計劃是否是符合預期的。