一次因表變量導致SQL執(zhí)行效率變慢的實戰(zhàn)記錄
場景
最近工作中,發(fā)現(xiàn)某同步JOB在執(zhí)行中經(jīng)常拋出SQL執(zhí)行超時的問題,查看日志發(fā)現(xiàn)每次SQL執(zhí)行的時間都是線性增長的,循環(huán)執(zhí)行50次以后執(zhí)行時間甚至超過了5分鐘
JOB執(zhí)行流程分析
首先,對于JOB流程進行分析,查看是否是JOB設計上的問題
通過對流程的分析,發(fā)現(xiàn)每次獲取的需要同步的數(shù)據(jù)最多只有一萬條,不存在大數(shù)據(jù)寫入導致超時的問題。
那么在對獲取詳細信息這個過程進行分析,發(fā)現(xiàn)關聯(lián)的表中最多的數(shù)據(jù)已經(jīng)上億了,可能是這里導致了整體SQL執(zhí)行變慢的原因。這里能算可疑點一。
再接著往下一個流程看與表B對比重復數(shù)據(jù)時,隨著循環(huán)執(zhí)行表B的數(shù)據(jù)會越來越多,那么會不會這里是導致循環(huán)執(zhí)行下執(zhí)行時間稱線性增長的主要原因呢。
逐一排除問題
之前我們通過分析JOB執(zhí)行流程,發(fā)現(xiàn)了兩個可疑點,那么現(xiàn)在具體分析SQL的問題
CREATE TABLE #TableTemp ( 字段A int null, 字段B int null, 字段C int null ) INSERT INTO #TableTemp( 字段A, 字段B )SELECT a.字段A, 字段B FROM ServerA.dbo.TableB a WITH(NOLOCK) LEFT JOIN dbo.TableA b WITH(NOLOCK) a.Id = b.Id UPDATE a SET a.字段C = b.字段D FROM #TableTemp a LEFT JOIN dbo.TableC b WITH(NOLOCK) ON a.字段A =b.id INSERT INTO dbo.目標TableA( 字段A, 字段B ) SELECT 字段A, 字段B FROM #TableTemp WITH(NOLOCK) INSERT INTO dbo.目標TableB( 字段A, 字段B, 字段C ) SELECT DISTINCT a.字段A, a.字段B, a.字段C FROM #TableTemp a WITH(NOLOCK) LEFT JOIN dbo.目標TableB b ON a.字段A = b.字段A AND a.字段B = b.字段B WHERE a.PK IS NULL
先來查看可疑點一,是不是這里出了問題。因為表TableC數(shù)據(jù)已經(jīng)是幾億的量,但單獨將該SQL執(zhí)行發(fā)現(xiàn),因為索引的存在發(fā)現(xiàn)執(zhí)行并不是特別慢,所以可以排除掉該問題
那么來看看可疑點二呢
INSERT INTO dbo.目標TableB( 字段A, 字段B, 字段C ) SELECT DISTINCT a.字段A, a.字段B, a.字段C FROM #TableTemp a WITH(NOLOCK) LEFT JOIN dbo.目標TableB b ON a.字段A = b.字段A AND a.字段B = b.字段B WHERE a.PK IS NULL
可以看到該SQL插入的同時還查詢了自身是否存在條件下相同的數(shù)據(jù),查看表目標TableB發(fā)現(xiàn),該表沒有主鍵也沒有索引,再通過DBA那邊提供的SQL分析發(fā)現(xiàn),這句SQL對于dbo.目標TableB進行了全表掃描,再加上插入的1W條數(shù)據(jù),相當于對于dbo.目標TableB全表掃描了1w次,隨著循環(huán)的執(zhí)行該表數(shù)據(jù)越來越多,執(zhí)行時間也就越來越長,看來這里就是導致執(zhí)行時間線性增長的主要原因了。
解決問題
根據(jù)上面問題的排除,我們已經(jīng)得知問題的關鍵所在就是進行了1w次的全表掃描,導致了SQL執(zhí)行時間過長,那么解決問題的關鍵所在就是避免這么多次的全表掃描。那么最直接的解決方法,就是建立索引避免全表掃描
1.通過使用臨時表代替表變量
先來看看,表變量與臨時表的區(qū)別,可以看到表變量是無法使用索引的,所以我們使用索引避免全表掃描的話必須要代替掉表變量,然后在臨時表的字段A上我們創(chuàng)建索引
2.修改目標TableB的寫入邏輯
現(xiàn)有寫入邏輯會先判斷是否在目標TableB中是否存在,不存在時則寫入表中,保持業(yè)務的情況下,我們稍微修改下邏輯,再寫入之前先排除掉與目標TableB中的數(shù)據(jù),將剩余數(shù)據(jù)寫入表中,就能避免循環(huán)1W次的目標TableB表查詢了
通過這兩處修改后,再執(zhí)行該JOB發(fā)現(xiàn)問題得到了完美的解決。
總結
到此這篇關于因表變量導致SQL執(zhí)行效率變慢的文章就介紹到這了,更多相關表變量導致SQL執(zhí)行變慢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
dapper使用Insert或update時部分字段不映射到數(shù)據(jù)庫
我們在使用dapper的insert或update方法時可能會遇見一些實體中存在的字段但是,數(shù)據(jù)庫中不存在的字段,這樣在使用insert時就是拋出異常提示字段不存在,這個時候該怎么解決呢,下面給大家分享示例實體代碼,感興趣的朋友一起看看吧2023-12-12PostgreSQL數(shù)據(jù)庫服務端監(jiān)聽設置及客戶端連接方法教程
這篇文章主要介紹了PostgreSQL數(shù)據(jù)庫服務端監(jiān)聽設置及客戶端連接方法,需要的朋友可以參考下2014-07-07在SQL SERVER中查詢數(shù)據(jù)庫中第幾條至第幾條之間的數(shù)據(jù)SQL語句寫法
這篇文章主要介紹了在SQL SERVER中查詢數(shù)據(jù)庫中第幾條至第幾條之間的數(shù)據(jù)SQL語句寫法,需要的朋友可以參考下2015-11-11