成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

深入了解SQL性能殺手FILTER操作

IT那活兒 / 2047人閱讀
深入了解SQL性能殺手FILTER操作

?????????????????點(diǎn)擊上方“IT那活兒”,關(guān)注后了解更多內(nèi)容,不管IT什么活兒,干就完了!?。?/span>


1

1

1


FILTER操作是執(zhí)行計(jì)劃中常見(jiàn)的操作,這種操作有兩種情況:

1.1  只有一個(gè)子節(jié)點(diǎn),那么就是簡(jiǎn)單過(guò)濾操作。(不是本文重點(diǎn)

1.2 有多個(gè)子節(jié)點(diǎn),那么就是類(lèi)似NESTED LOOPS操作,只不過(guò)與NESTED LOOPS差別在于,F(xiàn)ILTER內(nèi)部會(huì)構(gòu)建HASH表(有緩存提高效率,緩存的bucket數(shù)目是1024個(gè)),對(duì)于重復(fù)匹配的,不會(huì)再次進(jìn)行循環(huán)查找,而是利用已有結(jié)果,提高效率。
但是一旦重復(fù)匹配的較少,循環(huán)次數(shù)多,也就是類(lèi)似NESTED LOOPS,那么這種FILTER操作將是嚴(yán)重影響性能的操作,可能你的SQL幾天都執(zhí)行不完了。(本文討論重點(diǎn)


1

2

1


下面看看各種情況下的FILTER操作:
2.1 單子節(jié)點(diǎn):
很顯然ID=1的FILTER操作只有一個(gè)子節(jié)點(diǎn)ID=2,這種情況下的FILTER操作也就是單純的過(guò)濾操作。
2.2 多子節(jié)點(diǎn):
FILTER多子節(jié)點(diǎn)往往就是性能殺手,主要出現(xiàn)在子查詢(xún)無(wú)法UNNEST查詢(xún)轉(zhuǎn)換,經(jīng)常遇到的情況就是NOT IN子查詢(xún)、子查詢(xún)和OR連用、復(fù)雜子查詢(xún)、CBO未做子查詢(xún)UNNEST等情況。

1

3

1


3.1 NOT IN子查詢(xún)中的FILTER

先來(lái)看下NOT IN情況:
針對(duì)上面的NOT IN子查詢(xún),如果子查詢(xún)object_id有NULL存在,則整個(gè)查詢(xún)都不會(huì)有結(jié)果,在11g之前,如果主表和子表的object_id未同時(shí)有NOT NULL約束,或都未加IS NOT NULL限制,則ORACLE會(huì)走FILTER。11g有新的ANTI NA(NULL AWARE)優(yōu)化,可以對(duì)子查詢(xún)進(jìn)行UNNEST,從而提高效率。
對(duì)于未UNNEST的子查詢(xún),走了FILTER,有至少2個(gè)子節(jié)點(diǎn),執(zhí)行計(jì)劃還有個(gè)特點(diǎn)就是Predicate謂詞部分有:B1這種類(lèi)似綁定變量的東西,內(nèi)部操作走類(lèi)似NESTED LOOPS操作。
11g有NULL AWARE專(zhuān)門(mén)針對(duì)NOT IN問(wèn)題進(jìn)行優(yōu)化,如下所示:
通過(guò)NULL AWARE操作,對(duì)無(wú)法UNNEST的NOT IN子查詢(xún)可以轉(zhuǎn)換成JOIN形式,這樣效率就大幅度提升了。
如果在11g之前,遇到NOT IN無(wú)法UNNEST,那該怎么做呢?
  • 將NOT IN部分的匹配條件,針對(duì)本例就是ANTI_TEST1.object_id和ANTI_TEST2.object_id均設(shè)為NOT NULL約束;

  • 不改NOT NULL約束,則需要兩個(gè)object_id均增加IS NOT NULL條件;

  • 改為NOT EXISTS;

  • 改為ANTI JOIN形式。

以上四種方式,大部分情況下均能達(dá)到讓優(yōu)化器走JOIN的目的,如下所示:
以上寫(xiě)法執(zhí)行計(jì)劃都是一樣的,如下所示:
說(shuō)白了,unnest subquery就是轉(zhuǎn)換成JOIN形式,如果能轉(zhuǎn)換成JOIN就可以利用高效JOIN特性來(lái)提高操作效率,不能轉(zhuǎn)換就走FILTER,可能影響效率,11g的NULL AWARE從執(zhí)行計(jì)劃里可以看出,還是有點(diǎn)區(qū)別,沒(méi)有走INDEX FULL SCAN掃描,因?yàn)闆](méi)有條件讓ORACLE知道object_id可能存在NULL,所以也就走不了索引了。
OK,現(xiàn)在來(lái)說(shuō)一個(gè)數(shù)據(jù)庫(kù)升級(jí)過(guò)程中碰到的案例,背景是11.2.0.2升級(jí)到11.2.0.4后下面SQL出現(xiàn)性能問(wèn)題:
執(zhí)行計(jì)劃如下:
這里的ID=4和ID=8兩個(gè)FILTER均有2個(gè)子節(jié)點(diǎn),很顯然是NOT IN子查詢(xún)無(wú)法UNNEST導(dǎo)致的。
上面說(shuō)了在11g ORACLE CBO可以將NOT IN轉(zhuǎn)換成NULL AWARE ANTI JOIN,并且在11.2.0.2上是可以轉(zhuǎn)換的,到11.2.0.4上就不行了。
兩個(gè)FILTER操作的危害到底有多大呢,可以通過(guò)查詢(xún)實(shí)際執(zhí)行計(jì)劃來(lái)看:
使用ALTER SESSION SET STATISTICS_LEVEL=ALL;截取2分25s的記錄查看實(shí)際情況,ID=10步驟的CARD=141行就需要2分25s,主要是ID=11的索引較差,ID=11回表需要過(guò)濾大量數(shù)據(jù)。
實(shí)際此步驟有:27w行。
也就是這條SQL要運(yùn)行10天以上了,簡(jiǎn)直太恐怖了。
針對(duì)此問(wèn)題的分析如下:
  • 分析1:查詢(xún)和NULL AWARE ANTI JOIN相關(guān)的隱含參數(shù)是否有效;

  • 分析2:收集統(tǒng)計(jì)信息是否有效;

  • 分析3:是否是新版本BUG或者升級(jí)中修改了參數(shù)導(dǎo)致的。

針對(duì)第一種情況(分析1):
參數(shù)是TRUE,顯然沒(méi)有問(wèn)題。
針對(duì)第二種情況(分析2)
收集統(tǒng)計(jì)信息發(fā)現(xiàn)無(wú)效。
那么此時(shí),只能寄希望于第三種情況(分析3)可能是BUG或者升級(jí)過(guò)程中修改了其它參數(shù)影響了無(wú)法走NULL AWARE ANTI JOIN。
ORACLE BUG和參數(shù)那么多,那么我們?cè)趺纯焖僬业絾?wèn)題根源導(dǎo)致是哪個(gè)BUG或者參數(shù)導(dǎo)致的呢?
這里給大家分享一個(gè)神器SQLT,全稱(chēng)(SQLTXPLAIN),這是ORACLE內(nèi)部性能部門(mén)開(kāi)發(fā)的工具,可以在MOS上下載,功能非常強(qiáng)勁。
此工具詳細(xì)用法不做贅述,針對(duì)此工具,Apress也出了一本書(shū)籍,感興趣的可以學(xué)習(xí)一下:
回歸正題,現(xiàn)在要找出是不是新版本BUG或者修改了某個(gè)參數(shù)導(dǎo)致問(wèn)題產(chǎn)生,那么就要用到SQLT的高級(jí)方法:XPLORE。
XPLORE會(huì)針對(duì)ORACLE中的各種參數(shù)不停打開(kāi)、關(guān)閉,來(lái)輸出執(zhí)行計(jì)劃,最終我們可以通過(guò)生成的報(bào)告,找到匹配的執(zhí)行計(jì)劃來(lái)判斷是BUG問(wèn)題還是參數(shù)設(shè)置問(wèn)題。
使用很簡(jiǎn)單,參考readme.txt將需要測(cè)試的SQL多帶帶編輯一個(gè)文件,一般,我們測(cè)試都使用XPLAIN方法,調(diào)用EXPLAIN PLAN FOR進(jìn)行測(cè)試,這樣保證測(cè)試效率。
SQLT找出問(wèn)題根源:
最終通過(guò)SQLT XPLORE找出問(wèn)題根源在于新版本關(guān)閉了_optimier_squ_bottomup參數(shù)(和子查詢(xún)相關(guān))。
從這點(diǎn)上也可以看出來(lái),很多查詢(xún)轉(zhuǎn)換能夠成功,不光是一個(gè)參數(shù)起作用,可能多個(gè)參數(shù)共同作用。因此,關(guān)閉默認(rèn)參數(shù),除非有強(qiáng)大的理由,否則,不可輕易修改其默認(rèn)值。
至此,此問(wèn)題在SQLT的幫助下,快速得以解決,如果不使用SQLT,那么解決問(wèn)題的過(guò)程顯然更為曲折,一般情況下,估計(jì)是讓開(kāi)發(fā)先修改SQL了。
思考一下,原來(lái)的SQL是不是還可以更優(yōu)化呢?
很顯然,如果要進(jìn)一步優(yōu)化,要徹底對(duì)SQL進(jìn)行重寫(xiě)。
通過(guò)觀察,2個(gè)子查詢(xún)部分有相同點(diǎn),經(jīng)過(guò)分析語(yǔ)義:查找表DT_MBY_TEST_LOG在指定INSERT_TIME范圍內(nèi)的,按照每個(gè)TBILL_ID取最小的INSERT_TIME,并且ID不在子查詢(xún)中,然后結(jié)果按照INSERT_TIME排序,最后取TOP 199。
原SQL使用自連接、兩個(gè)子查詢(xún),冗余繁雜。自然想到用分析函數(shù)進(jìn)行改寫(xiě),避免自連接,從而提高效率。
改寫(xiě)后的SQL如下:
執(zhí)行計(jì)劃:
至此,這條SQL從原來(lái)的走FILTER需要耗時(shí)10天,到找出問(wèn)題根源可以走NULL AWARE ANTI JOIN需要耗時(shí)7秒多,最后通過(guò)徹底改寫(xiě)耗時(shí)3.8s。

3.2 OR子查詢(xún)中的FILTER

再來(lái)看下常見(jiàn)的OR與子查詢(xún)連用情況,在實(shí)際優(yōu)化過(guò)程中,遇到OR與子查詢(xún)連用,一般都不能unnest subquery了,可能會(huì)導(dǎo)致嚴(yán)重性能問(wèn)題,OR與子查詢(xún)連用有兩種可能:
  • condition or subquery;

  • subquery內(nèi)部包含or,如in (select … from tab where condition1 or condition 2)。

通過(guò)一個(gè)具體案例,分享下對(duì)于OR子查詢(xún)優(yōu)化的處理方式,在某庫(kù)11g R2中碰到如下SQL,幾個(gè)小時(shí)都沒(méi)有執(zhí)行完:
1)先來(lái)看下執(zhí)行計(jì)劃:
2)怎么通過(guò)看到這個(gè)執(zhí)行計(jì)劃,一眼定位性能慢的原因呢?主要通過(guò)下列幾點(diǎn)來(lái)分析定位:
  • 執(zhí)行計(jì)劃中的Rows,也就是每個(gè)步驟返回的cardinality很少,都是幾行,在分析表也不是太大,那么怎么可能導(dǎo)致運(yùn)行幾個(gè)小時(shí)都執(zhí)行不完呢?
    執(zhí)行時(shí)間與執(zhí)行計(jì)劃關(guān)鍵指標(biāo)不匹配。很大原因可能就在于統(tǒng)計(jì)信息不準(zhǔn),導(dǎo)致CBO優(yōu)化器估算錯(cuò)誤,錯(cuò)誤的統(tǒng)計(jì)信息導(dǎo)致錯(cuò)誤的執(zhí)行計(jì)劃,這是第一點(diǎn)。
  • 看ID=15到18部分,它們是ID=1 FILTER操作的第二子節(jié)點(diǎn),第一子節(jié)點(diǎn)是ID=2部分,很顯然,如果ID=2部分估算的cardinality錯(cuò)誤,實(shí)際情況很大的話,那么對(duì)ID=15到18部分四個(gè)表全掃描次數(shù)將會(huì)巨大,那么也就導(dǎo)致災(zāi)難產(chǎn)生。
  • 很顯然,ID=2部分的一堆NESTED LOOPS也是很可疑的,找到ID=2操作的入口在ID=6部分,全表掃描DEALREC_ERR_201608,估算返回1行,很顯然,這是導(dǎo)致NESTED LOOPS操作的根源,因此,需要檢驗(yàn)其準(zhǔn)確性。
主表DEALREC_ERR_201608在ID=6查詢(xún)條件中經(jīng)查要返回2000w行,計(jì)劃中估算只有1行,因此,會(huì)導(dǎo)致NESTED LOOPS次數(shù)實(shí)際執(zhí)行千萬(wàn)次,導(dǎo)致效率低下,應(yīng)該走HASH JOIN,需要更新統(tǒng)計(jì)信息。
另外ID=1是FILTER,它的子節(jié)點(diǎn)是ID=2和ID=15、16、17、18,同樣的ID 15-18也被驅(qū)動(dòng)千萬(wàn)次。
找出問(wèn)題根源后,逐步解決。首先要解決ID=6部分針對(duì)DEALREC_ERR_201608表按照查詢(xún)條件substr(other_class, 1, 3) NOT IN (‘147’,‘151’, …)獲得的cardinality的準(zhǔn)確性,也就是要收集統(tǒng)計(jì)信息。
然而發(fā)現(xiàn)使用size auto,size repeat,對(duì)other_class收集直方圖均無(wú)效果,執(zhí)行計(jì)劃中對(duì)other_class的查詢(xún)條件返回行估算還是1(實(shí)際2000w行)。
3)再次執(zhí)行后的執(zhí)行計(jì)劃如下:
  • DEALREC_ERR_201608與B_DEALING_DONE_TYPE原來(lái)走NL的現(xiàn)在正確走HASH JOIN。Build table是小結(jié)果集,probe table是ERR表大結(jié)果集,正確。

  • 但是ID=2與ID=11到14,也就是與TMI_NO_INFOS的OR子查詢(xún),還是FILTER,驅(qū)動(dòng)數(shù)千萬(wàn)次子節(jié)點(diǎn)查詢(xún),下一步優(yōu)化要解決的問(wèn)題。

  • 性能從12小時(shí)到2小時(shí)。

現(xiàn)在要解決的就是FILTER問(wèn)題,對(duì)子查詢(xún)有OR條件的,簡(jiǎn)單條件如果能夠查詢(xún)轉(zhuǎn)換,一般會(huì)轉(zhuǎn)為一個(gè)union all view后再進(jìn)行semi join、anti join(轉(zhuǎn)換成union all view,如果謂詞類(lèi)型不同,則SQL可能會(huì)報(bào)錯(cuò))。
對(duì)于這種復(fù)雜的,優(yōu)化器就無(wú)法查詢(xún)轉(zhuǎn)換了,因此,改寫(xiě)是唯一可行的方法。
分析SQL,原來(lái)查詢(xún)的是同一張表,而且條件類(lèi)似,只是取的長(zhǎng)度不同,那么就好辦了!
4)如何讓帶OR的子查詢(xún)執(zhí)行計(jì)劃從FILTER變成JOIN。兩種方法:
  • 方法1:改為UNION ALL/UNION;

  • 方法2:語(yǔ)義改寫(xiě).前面已經(jīng)使用語(yǔ)義改寫(xiě),內(nèi)部轉(zhuǎn)為了類(lèi)似UNION的操作,如果要繼續(xù)減少表的訪問(wèn),則只能徹改寫(xiě)OR條件,避免轉(zhuǎn)換為UNION操作。

5)再來(lái)分析下原始OR條件:
上面含義是ERR表的TMISID截取前8,9,10,11位與TMI_NO_INFOS.BILLID_HEAD匹配,對(duì)應(yīng)匹配BILLID_HEAD長(zhǎng)度正好為8,9,10,11。
很顯然,語(yǔ)義上可以這樣改寫(xiě):
ERR表與TMI_NO_INFOS表關(guān)聯(lián),ERR.TMISID前8位與ITMI_NO_INFOS.BILLID_HEAD長(zhǎng)度在8-11之間的前8位完全匹配,在此前提下,TMISID like BILLID_HEAD ||’%’。
6)現(xiàn)在就動(dòng)手徹底改變多個(gè)OR子查詢(xún),讓SQL更加精簡(jiǎn),效率更高。改寫(xiě)如下:
7)執(zhí)行計(jì)劃如下:
現(xiàn)在的執(zhí)行計(jì)劃終于變的更短,更易讀,通過(guò)邏輯改寫(xiě)走了HASH JOIN,最終一條返回300多萬(wàn)行數(shù)據(jù)的SQL原先需要12小時(shí)運(yùn)行的SQL,現(xiàn)在3分鐘就執(zhí)行完了。
思考:結(jié)構(gòu)良好,語(yǔ)義清晰的SQL編寫(xiě),有助于優(yōu)化器選擇更合理的執(zhí)行計(jì)劃,所以說(shuō),寫(xiě)好SQL也是門(mén)技術(shù)活。
通過(guò)上述這個(gè)案例,希望能給大家一些啟發(fā),寫(xiě)SQL如何能夠自己充當(dāng)查詢(xún)轉(zhuǎn)換器,編寫(xiě)的SQL能夠減少表、索引、分區(qū)等的訪問(wèn),能夠讓ORACLE更易使用一些高效算法進(jìn)行運(yùn)算,從而提高SQL執(zhí)行效率。
其實(shí),OR子查詢(xún)也不一定就完全不能unnest,只是絕大多數(shù)情況下無(wú)法unnest而已,請(qǐng)看下例:
8)不可unnest的查詢(xún):
9)可以u(píng)nnest的查詢(xún):
這2條SQL的差別也就是將條件or id3=id2+1000轉(zhuǎn)換成or id3-1000=id2,前者不可以u(píng)nnest,后者可以u(píng)nnest,通過(guò)分析10053可以得知:
10)不可unnest的出現(xiàn):
  • SU: Unnesting query blocks in query block SEL$1 (#1) that are valid to unnest;

  • Subquery Unnesting on query block SEL$1 (#1)SU: Performing unnesting that does not require costing;

  • SU: Considering subquery unnest on query block SEL$1 (#1);

  • SU:   Checking validity of unnesting subquery SEL$2 (#2);

  • SU:   SU bypassed: Invalid correlated predicates;

  • SU:   Validity checks failed。

11)可以u(píng)nnest的出現(xiàn):
并且將SQL改寫(xiě)為:
最終CBO先查詢(xún)T3條件,做個(gè)UNION ALL視圖,之后與T2關(guān)聯(lián)。
從這里來(lái)看,對(duì)于OR子查詢(xún)的unnest要求比較嚴(yán)格,從這條語(yǔ)句分析,ORACLE可進(jìn)行unnest必須要求對(duì)主表列不要進(jìn)行運(yùn)算操作,優(yōu)化器自身并未將+1000條件左移,正因?yàn)閲?yán)格,所以大部分情況下,OR子查詢(xún)也就無(wú)法進(jìn)行unnest了,從而導(dǎo)致各種性能問(wèn)題。
3.3 類(lèi)FILTER問(wèn)題
主要體現(xiàn)在UPDATE關(guān)聯(lián)更新和標(biāo)量子查詢(xún)中,雖然此類(lèi)SQL語(yǔ)句中并未顯式出現(xiàn)FILTER關(guān)鍵字,但是內(nèi)部操作和FILTER操作如出一轍。
1)先看下UPDATE關(guān)聯(lián)更新:
這里需要更新14999行,執(zhí)行計(jì)劃如下:
ID=2部分是where exists選擇部分,先把需要更新的條件查詢(xún)出來(lái),之后執(zhí)行UPDATE關(guān)聯(lián)子查詢(xún)更新,可以看到ID=5部分出現(xiàn)綁定變量:B1,顯然UPDATE操作就類(lèi)似于原來(lái)的FILTER,對(duì)于選出的每行與子查詢(xún)表NEW_TAB關(guān)聯(lián)查詢(xún),如果ID列重復(fù)值較少,那么子查詢(xún)執(zhí)行的次數(shù)就會(huì)很多,從而影響效率,也就是ID=5的操作要執(zhí)行很多次。
當(dāng)然,這里字段ID唯一性很強(qiáng),可以建立UNIQUE INDEX,普通INDEX燈,這樣第5步就可以走索引了。
這里為了舉例這種UPDATE的優(yōu)化方式,不建索引,也可以搞定這樣的UPDATE:MERGR和UPDATE INLINE VIEW方式。
MERGE中直接利用HASH JOIN,避免多次訪問(wèn)操作,從而效率大增,再來(lái)看看UPDATE LINE VIEW寫(xiě)法:
UPDATE
(SELECT a.status astatus,
b.status bstatus
FROM old_tab a,
new_tab b
WHERE a.id=b.id
AND a.id >9000000
)
SET astatus=bstatus;
要求b.id是preserved key (唯一索引、唯一約束、主鍵),11g bypass_ujvc會(huì)報(bào)錯(cuò),類(lèi)似MERGE操作。
2)再來(lái)看看標(biāo)量子查詢(xún),標(biāo)量子查詢(xún)往往也是引發(fā)嚴(yán)重性能問(wèn)題的殺手。
標(biāo)量子查詢(xún)的計(jì)劃和普通計(jì)劃的執(zhí)行順序不同,標(biāo)量子查詢(xún)雖然在上面,但是它由下面的CUSTOMERS表結(jié)果驅(qū)動(dòng)(上面的在后面執(zhí)行,這個(gè)與普通執(zhí)行計(jì)劃順序不同),每行驅(qū)動(dòng)查詢(xún)一次標(biāo)量子查詢(xún)(有CACHE例外),同樣類(lèi)似FILTER操作。
如果對(duì)標(biāo)量子查詢(xún)進(jìn)行優(yōu)化,一般就是改寫(xiě)SQL,將標(biāo)量子查詢(xún)改為外連接形式(在約束和業(yè)務(wù)滿(mǎn)足的情況下也可改寫(xiě)為普通JOIN):
通過(guò)改寫(xiě)之后效率大增,并且使用HASH JOIN算法。
3)下面看一下標(biāo)量子查詢(xún)中的CACHE(FILTER和UPDATE關(guān)聯(lián)更新類(lèi)似),如果關(guān)聯(lián)的列重復(fù)值特別多,那么子查詢(xún)執(zhí)行次數(shù)就會(huì)很少,這時(shí)候效率會(huì)比較好。
標(biāo)量子查詢(xún)和FILTER一樣,有CACHE,如上面的emp_a有108K的行,但是重復(fù)的department_id只有11,這樣只查詢(xún)只掃描11次,掃描子查詢(xún)表的次數(shù)少了,效率會(huì)提升。
針對(duì)FILTER性能殺手問(wèn)題,主要分享這3點(diǎn)(3.1,3.2,3.3),當(dāng)然,還有很多其它值得注意的地方,這需要我們?nèi)粘6嗔粜暮头e累,從而熟悉優(yōu)化器一些問(wèn)題的處理方法。


1

4

1


數(shù)據(jù)物理分布對(duì)FILTER節(jié)點(diǎn)執(zhí)行次數(shù)的影響。

案例如下:
1)在t2表中插入1024行數(shù)據(jù):
DROP TABLE t2;
CREATE TABLE t2 AS SELECT LEVEL ID FROM dual CONNECT BY LEVEL<=1024;
2)反復(fù)執(zhí)行5次insert into:
INSERT INTO t2 SELECT*FROM t2;
COMMIT;
對(duì)應(yīng)的SQL如下:

SELECT COUNT(*)
FROM   t2
WHERE ID NOT IN
(SELECT ID
FROM(SELECT ID
FROM   t2
ORDER BY ID DESC)
WHERE ROWNUM<=100);
以上SQL的含義很簡(jiǎn)單,也就是對(duì)T2表中的ID降序排列,查詢(xún)不在前100的數(shù)據(jù)量,然而執(zhí)行卻比正常的慢很多(這里作為演示,只是構(gòu)造少量數(shù)據(jù),實(shí)際數(shù)據(jù)量很多,SQL執(zhí)行非常慢)。
執(zhí)行計(jì)劃如下所示:
通過(guò)前面有關(guān)FILTER內(nèi)容可以知道,表T2的ID只有1024個(gè)不同值,由于FILTER有緩存,那么這個(gè)子節(jié)點(diǎn)正常的執(zhí)行次數(shù)應(yīng)該是1024次,但是上述執(zhí)行計(jì)劃的執(zhí)行次數(shù)卻是12432次,子節(jié)點(diǎn)的執(zhí)行次數(shù)增加N倍是導(dǎo)致SQL變慢的主要原因。
解決這個(gè)問(wèn)題,主要要搞清楚為什么執(zhí)行次數(shù)不是1024次,在實(shí)際的應(yīng)用中,表是按天分表的,每天的數(shù)據(jù)累計(jì)到前一天,執(zhí)行計(jì)劃未變,但是突然某一天變慢,通過(guò)分析,出現(xiàn)這種情況的原因,大概率是數(shù)據(jù)的分布不同。
由于這里是按照ID構(gòu)造HASH表,可以測(cè)試下按照ID順序重新組織是什么情況。
DROP TABLE t3;
CREATE TABLE t3 AS SELECT*FROM t2 ORDER BY ID;--按照關(guān)聯(lián)列ID重新組織順序
執(zhí)行下列語(yǔ)句:
SELECT COUNT(*)
FROM   t3
WHERE ID NOT IN
(SELECT ID
FROM(SELECT ID
FROM   t3
ORDER BY ID DESC)WHERE ROWNUM<=100);
執(zhí)行計(jì)劃如下:
現(xiàn)在執(zhí)行計(jì)劃中子節(jié)點(diǎn)執(zhí)行次數(shù)是1024次了,的確是數(shù)據(jù)的物理分布原因,看來(lái)FITER算法還不夠完善,這點(diǎn)值得注意。
如果要進(jìn)一步優(yōu)化上述語(yǔ)句,可以通過(guò)改寫(xiě)成NOT EXISTS避免FILTER來(lái)提高效率,改寫(xiě)如下:
SELECT COUNT(*)
FROM   t3 a
WHERE not exists
(SELECT 1 from
(SELECT ID
FROM(SELECT ID
FROM   t3
ORDER BY ID DESC)WHERE ROWNUM<=100) b
where a.ID = b.ID
);
通過(guò)執(zhí)行計(jì)劃可以看出,改寫(xiě)為NOT EXISTS后走HASH JOIN效率得到極大提升。


1

5

1


通過(guò)本文可以了解到,F(xiàn)ILTER往往是導(dǎo)致SQL執(zhí)行性能緩慢的元兇,主要是由于子查詢(xún)未做UNNEST SUBQUERY查詢(xún)轉(zhuǎn)換,未UNNEST的原因有很多,比如統(tǒng)計(jì)信息不準(zhǔn),如果發(fā)現(xiàn)統(tǒng)計(jì)信息準(zhǔn)確了還是無(wú)法UNNEST,那么要考慮SQL寫(xiě)法是否遇到優(yōu)化器的限制或BUG,比如OR子查詢(xún)。
當(dāng)然,F(xiàn)ILTER由于內(nèi)部構(gòu)建HASH表,有緩存和HASH算法,對(duì)特定的查詢(xún)效率可能不錯(cuò),很顯然是要求關(guān)聯(lián)條件的重復(fù)值較少,這樣子節(jié)點(diǎn)執(zhí)行次數(shù)少,從而提高效率,所以在實(shí)際應(yīng)用和優(yōu)化中,還需要具體問(wèn)題具體分析。



本文作者:丁 俊

本文來(lái)源:IT那活兒(上海新炬王翦團(tuán)隊(duì))

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/129606.html

相關(guān)文章

  • Cloud Foundry——Azure殺手?

    摘要:最近推出了獨(dú)具創(chuàng)新的。能否戰(zhàn)勝微軟事實(shí)上,的血統(tǒng)將嚴(yán)重影響到它成為企業(yè)的可行性選擇,它不會(huì)吸引用戶(hù)。微軟的在成熟性上更好,而且它的備份是通過(guò)自身的專(zhuān)用基礎(chǔ)設(shè)施。的基礎(chǔ)構(gòu)建被擺在了微軟商店首要位置上。是針對(duì)開(kāi)發(fā)者和并不熱衷于微軟的商店。 VMware最近推出了獨(dú)具創(chuàng)新的Cloud Foundry。這款平臺(tái)及服務(wù)無(wú)疑有著新派傾向:用戶(hù)將可以注冊(cè)并開(kāi)發(fā)像MySQL和MongoDB這樣的運(yùn)行數(shù)據(jù)庫(kù)...

    yy13818512006 評(píng)論0 收藏0
  • PHP 性能分析第三篇: 性能調(diào)優(yōu)實(shí)戰(zhàn)

    摘要:注意本文是我們的性能分析系列的第三篇,點(diǎn)此閱讀性能分析第一篇介紹,或性能分析第二篇深入研究。小的性能提升很可能來(lái)自?xún)?yōu)化,而非緩存。注意此更改已提交到并已獲更新。目前,兩者具備相同的特性,只有一些部分重命名了。 注意:本文是我們的 PHP 性能分析系列的第三篇,點(diǎn)此閱讀?PHP 性能分析第一篇: XHProf & XHGui 介紹?,或??PHP 性能分析第二篇: 深入研究 XHGui...

    cnsworder 評(píng)論0 收藏0
  • 我的 2015 年度小結(jié)(技術(shù)方面)

    摘要:因?yàn)槁酚蓪用媸軜I(yè)務(wù)影響很大,經(jīng)常修改一些功能的行為,所以后來(lái)大部分測(cè)試都是針對(duì)層面的單元測(cè)試。在我了解的過(guò)程中,我發(fā)現(xiàn)中文網(wǎng)絡(luò)上對(duì)的討論非常分散,于是我創(chuàng)建了中文社區(qū),到年末已經(jīng)有個(gè)注冊(cè)用戶(hù)和個(gè)帖子了。 https://jysperm.me/2016/02/programming-of-2015/ 從 2014 年末開(kāi)始開(kāi)發(fā)的一個(gè)互聯(lián)網(wǎng)金融項(xiàng)目終于在今年三月份上線了,這是一個(gè) Node...

    宋華 評(píng)論0 收藏0
  • 我的 2015 年度小結(jié)(技術(shù)方面)

    摘要:因?yàn)槁酚蓪用媸軜I(yè)務(wù)影響很大,經(jīng)常修改一些功能的行為,所以后來(lái)大部分測(cè)試都是針對(duì)層面的單元測(cè)試。在我了解的過(guò)程中,我發(fā)現(xiàn)中文網(wǎng)絡(luò)上對(duì)的討論非常分散,于是我創(chuàng)建了中文社區(qū),到年末已經(jīng)有個(gè)注冊(cè)用戶(hù)和個(gè)帖子了。 https://jysperm.me/2016/02/programming-of-2015/ 從 2014 年末開(kāi)始開(kāi)發(fā)的一個(gè)互聯(lián)網(wǎng)金融項(xiàng)目終于在今年三月份上線了,這是一個(gè) Node...

    Nosee 評(píng)論0 收藏0
  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類(lèi)與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類(lèi)對(duì)象鎖和類(lèi)鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類(lèi)單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    spacewander 評(píng)論0 收藏0
  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類(lèi)與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類(lèi)對(duì)象鎖和類(lèi)鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類(lèi)單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    xfee 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<