{eval=Array;=+count(Array);}
如果數(shù)據(jù)量小的表,這樣的設(shè)計(jì)意義不大,而且當(dāng)然是單表速度快。若在大數(shù)據(jù)量情況下,設(shè)計(jì)非常有意義。在多表連接中注意數(shù)據(jù)的條目和外健,避免出行大量冗余數(shù)據(jù)導(dǎo)致性能下降。下面我以O(shè)racle講講數(shù)據(jù)查詢的整個(gè)過(guò)程技術(shù)。
由于數(shù)據(jù)分布到數(shù)據(jù)塊,在大量數(shù)據(jù)設(shè)計(jì)中可以將數(shù)據(jù)存儲(chǔ)于多個(gè)數(shù)據(jù)塊,在高并發(fā)進(jìn)程的隨機(jī)訪問(wèn)的情況下,能有效減少塊沖突 同樣的數(shù)據(jù)需要更多的數(shù)據(jù)塊來(lái)存儲(chǔ),由于數(shù)據(jù)塊的塊頭元信息大小固定,所以需要更多的空間來(lái)存儲(chǔ)塊頭元信息。行長(zhǎng)度過(guò)大容易導(dǎo)致行連接,從而導(dǎo)致Oracle獲取數(shù)據(jù)塊的效率降低 ,在行長(zhǎng)度固定的前提下,單塊能夠存儲(chǔ)更多的數(shù)據(jù)行,也就意味著Oracle一次I/O能讀取更多的數(shù)據(jù)行。適合連續(xù)順序讀或者存放大對(duì)象數(shù)據(jù)(如LOB數(shù)據(jù)) 由于大數(shù)據(jù)塊可以存放更多的索引葉節(jié)點(diǎn)信息,容易引起爭(zhēng)用,所以大數(shù)據(jù)塊不適合存放索引葉節(jié)點(diǎn)信息。
大量數(shù)據(jù)表的數(shù)據(jù)庫(kù)參數(shù)設(shè)置DB_FILE_MULTIBLOCK_READ_COUNT表示Oracle一次順序I/O讀操作最多能讀取的數(shù)據(jù)塊塊數(shù)。該參數(shù)的默認(rèn)值隨操作系統(tǒng)的不同而不同。在全表掃描或者索引快速掃描比較多的系統(tǒng)中(如DSS系統(tǒng)),建議將該值設(shè)置得較大。但是DB_FILE_MULTIBLOCK_READ_COUNT參數(shù)受操作最大單次I/O大小的限制,大多數(shù)操作系統(tǒng)單次讀操作的大小不能超過(guò)1MB,這也就意味著在8KB數(shù)據(jù)塊大小的情況下,該參數(shù)最大值為128。值得一提的是,該參數(shù)的大小還會(huì)影響Oracle CBO對(duì)執(zhí)行計(jì)劃的評(píng)估,如果設(shè)成較大值,Oracle的執(zhí)行計(jì)劃傾向于全表掃描。當(dāng)該參數(shù)設(shè)置為0或者保持默認(rèn)時(shí),CBO假設(shè)全表掃描時(shí)最多能連續(xù)讀取8個(gè)數(shù)據(jù)塊。從Oracle 11R2開始,DB_FILE_MULTIBLOCK_READ_COUNT的取值算法如下:
db_file_multiblock_read_count = min(1048576/db_block_size , db_cache_size/
(sessions * db_block_size))
注意 數(shù)據(jù)庫(kù)參數(shù)BLOCK_SIZE在設(shè)定之后,在數(shù)據(jù)庫(kù)生命周期內(nèi)不可更改。
當(dāng)執(zhí)行SELECT語(yǔ)句時(shí),如果在內(nèi)存里找不到相應(yīng)的數(shù)據(jù),就會(huì)從磁盤讀取進(jìn)而緩存至LRU末端(冷端),這個(gè)過(guò)程就叫物理讀。當(dāng)相應(yīng)數(shù)據(jù)已在內(nèi)存,就會(huì)邏輯讀。我物理讀是磁盤讀,邏輯讀是內(nèi)存讀;內(nèi)存讀的速度遠(yuǎn)比磁盤讀來(lái)得快。
下面將本人大數(shù)據(jù)分區(qū)設(shè)計(jì)截圖,為大家參考學(xué)習(xí)。
先貼倆圖鎮(zhèn)鎮(zhèn)場(chǎng)。
對(duì)于內(nèi)連接,使用單個(gè)查詢是有意義的,因?yàn)槟阒猾@得匹配的行。
對(duì)于左連接,多個(gè)查詢要好得多。
看看下面的基準(zhǔn)測(cè)試:
5個(gè)連接的單個(gè)查詢
查詢:8.074508秒
結(jié)果大小:2268000
一行5個(gè)查詢
組合查詢時(shí)間:0.00262秒
結(jié)果大小:165 (6 + 50 + 7 + 12 + 90)
注意,我們?cè)趦煞N情況下得到了相同的結(jié)果(6 x 50 x 7 x 12 x 90 = 2268000)
對(duì)于冗余數(shù)據(jù),左連接使用更多的內(nèi)存。
如果只執(zhí)行兩個(gè)表的連接,那么內(nèi)存限制可能沒(méi)有那么糟糕,但通常是三個(gè)或更多的表,因此值得進(jìn)行不同的查詢。
用過(guò)Laravel嗎?還記得 Eloquent ORM模型嗎?
不知道有沒(méi)有注意到,debug所打印出來(lái)的多表聯(lián)合查詢,
都是拆分為“單個(gè)表查詢”,然后使用PHP處理的。
Happy coding :-)
我是@程序員小助手,持續(xù)分享編程知識(shí),歡迎關(guān)注。
是做表連接查詢還是做分解查詢要具體情況具體分析。
如果數(shù)據(jù)庫(kù)的結(jié)構(gòu)合理,索引設(shè)計(jì)得當(dāng),表連接的效率要高于分解查詢。比如,在有外鍵的時(shí)候,數(shù)據(jù)庫(kù)可以為外鍵建表并建立索引從而提升多個(gè)表連接查詢的效率。另外,多表連接查詢不需要把數(shù)據(jù)傳輸?shù)綉?yīng)用程序中,直接在數(shù)據(jù)庫(kù)端執(zhí)行,這在很大程度上提升了效率。
但是多表連接也有一些缺點(diǎn)。多表連接對(duì)表結(jié)構(gòu)的依存度很高,只要表結(jié)構(gòu)出現(xiàn)變更就會(huì)同時(shí)對(duì)數(shù)據(jù)庫(kù)檢索和應(yīng)用處理兩個(gè)部分產(chǎn)生較大影響。另外,多表連接的兼容性不好,數(shù)據(jù)庫(kù)不同SQL文也多少有些差異。而且采用分散數(shù)據(jù)庫(kù)的時(shí)候,實(shí)現(xiàn)多表連接即麻煩又沒(méi)有什么好處。因此,一些大型系統(tǒng)或者是支持多種類數(shù)據(jù)庫(kù)的系統(tǒng)一般不會(huì)使用多表連接,而傾向于采用分解查詢。
這個(gè)得看情況,一般數(shù)據(jù)不大的情況下多表連接查詢和多次單表查詢的效率差不多。如果數(shù)據(jù)量足夠大,那肯定是多次單表查詢的效率更高。在很多大的公司里面,都會(huì)禁用多表連接查詢,原因就是一旦數(shù)據(jù)量足夠大的時(shí)候多表連接查詢效率會(huì)很慢,而且不利于分庫(kù)分表的查詢優(yōu)化。那么看一下下面這個(gè)例子。
我這里有一個(gè)數(shù)據(jù)庫(kù),我們拿里面的客戶表和地區(qū)表做兩種查詢的對(duì)比。用戶表數(shù)據(jù)是31萬(wàn)條,地區(qū)表3511條。
1. 使用連表查詢成都市的客戶總數(shù)
2.使用多次單表查詢客戶總數(shù)
可以看到,查詢出來(lái)的結(jié)果都是一樣,但是第一種的連表查詢用了0.67秒中,而第二種多次單表查詢一共用時(shí)0.14秒。這個(gè)對(duì)比已經(jīng)是很明顯了吧。
雖然這只是一個(gè)很簡(jiǎn)單的例子,但是對(duì)比結(jié)果是非常明顯的。在實(shí)際應(yīng)用中可能會(huì)更復(fù)雜、數(shù)據(jù)更多,如果還使用連表查詢時(shí)非常慢的,而且還消耗服務(wù)器資源。
所以現(xiàn)在在很多大了公司明確要求禁止使用join查詢,比如ucloud、ucloud就明確規(guī)定禁用三表以上的join查詢。
1. 多次單表查詢,讓緩存的效率更高。
許多應(yīng)用程序可以方便地緩存單表查詢對(duì)應(yīng)的結(jié)果對(duì)象。另外對(duì)于MySQL的查詢緩存來(lái)說(shuō),如果關(guān)聯(lián)中的某個(gè)表發(fā)生了變化,那么就無(wú)法使用查詢緩存了,而拆分后,如果某個(gè)表很少改變,那么基于該表的查詢就可以重復(fù)利用查詢緩存結(jié)果了。
2. 將查詢分解后,執(zhí)行單個(gè)查詢可以減少鎖的競(jìng)爭(zhēng)。
3. 在應(yīng)用層做關(guān)聯(lián),更容易對(duì)數(shù)據(jù)庫(kù)進(jìn)行拆分,更容易做到高性能和可擴(kuò)展。
4. 查詢本身效率也可能會(huì)有所提升。
5. 可以減少冗余記錄的查詢。
6. 在應(yīng)用中實(shí)現(xiàn)了哈希關(guān)聯(lián),而不是使用MySQL的嵌套環(huán)關(guān)聯(lián),某些場(chǎng)景哈希關(guān)聯(lián)的效率更高很多。
7. 單表查詢有利于后期數(shù)據(jù)量大了分庫(kù)分表,如果聯(lián)合查詢的話,一旦分庫(kù),原來(lái)的sql都需要改動(dòng)。
8. 很多大公司明確規(guī)定禁用join,因?yàn)閿?shù)據(jù)量大的時(shí)候查詢確實(shí)很慢
所以在數(shù)據(jù)量不大的情況下,兩種方式的查詢都沒(méi)什么明顯的差別,使用多表連接查詢更方便。但是在數(shù)據(jù)量足夠大幾十萬(wàn)、幾百萬(wàn)甚至上億的數(shù)據(jù),或者在一些高并發(fā)、高性能的應(yīng)用中,一般建議使用單表查詢。
如果覺(jué)得笨貓的回答對(duì)你有用,點(diǎn)個(gè)關(guān)注,非常感謝。
先說(shuō)結(jié)論:不一定。
多表查詢效率低的時(shí)候,可以考慮拆解sql成多個(gè)小的sql,至于效率是否一定會(huì)提高,這個(gè)還不一定,具體問(wèn)題具體問(wèn)題。當(dāng)多表查詢效率低的時(shí)候,拆解成單個(gè)小sql,這只是一個(gè)可能的思路,起不起作用,不一定。
sql是一個(gè)很復(fù)雜的東西,sql引擎會(huì)分析執(zhí)行計(jì)劃,并可能按照他認(rèn)為最優(yōu)的執(zhí)行計(jì)劃執(zhí)行sql,但他認(rèn)為的也不一定是正確的。不同的sql執(zhí)行計(jì)劃不一樣,所以很難斷定sql拆解或者合并的效率。
說(shuō)了這么多,那到底是多表聯(lián)合查詢還是拆解呢?有沒(méi)有一個(gè)原則? 有!如果你確定你的單個(gè)sql的執(zhí)行效率比較快,當(dāng)然可以寫多個(gè)單個(gè)sql。當(dāng)然了,具備這個(gè)能力需要你對(duì)數(shù)據(jù)庫(kù)足夠了解,比如什么時(shí)候走索引,什么時(shí)候nested loop等等。如果你現(xiàn)在的多表聯(lián)合查詢比較慢,你需要找出來(lái)慢的原因,并分析拆解后的sql的執(zhí)行計(jì)劃,看是否避免了多表聯(lián)合查詢的效率問(wèn)題。
總之吧。這個(gè)問(wèn)題,只能給你一個(gè)大體的思路,因?yàn)闋砍兜胶芏嗷A(chǔ)問(wèn)題,我覺(jué)得最起碼sql執(zhí)行計(jì)劃應(yīng)該需要了解,一個(gè)sql可能的執(zhí)行計(jì)劃有幾十中,復(fù)雜sql的執(zhí)行計(jì)劃又是這幾十種的組合。哪種效率低,哪種效率高應(yīng)該有個(gè)大體了解。
多表查詢可以很快,也可以很慢。主要看執(zhí)行計(jì)劃。
單次肯定是多表連接查詢的效率高,但多次單表查詢的吞吐量高,而且容易優(yōu)化,例如分庫(kù)分表,使用緩存減少DB訪問(wèn)次數(shù)等等,所以在大數(shù)據(jù)量高并發(fā)場(chǎng)景通常使用多次單表查詢的方式。另外,不管是單表還是多表連接查詢,SQL的執(zhí)行時(shí)間和數(shù)據(jù)量、并發(fā)量都有很大關(guān)系,和掃描的數(shù)據(jù)行數(shù)也很有關(guān)系。如果一條SQL,平時(shí)執(zhí)行一次要2秒,10個(gè)并發(fā)時(shí),系統(tǒng)可能一點(diǎn)問(wèn)題都沒(méi)有,1000個(gè)并發(fā)時(shí),數(shù)據(jù)庫(kù)可能就被拖死了。我們組之前碰到過(guò)好幾次這種問(wèn)題,一張只有幾萬(wàn)條數(shù)據(jù)的表,因?yàn)橥浖铀饕綍r(shí)執(zhí)行只有幾百毫秒,高峰期直接飆到幾十秒,DB差點(diǎn)被拖垮。
單純從效率來(lái)講,join的表不太多時(shí),join效率比較高。但是占用的主要是數(shù)據(jù)庫(kù)服務(wù)器的資源。數(shù)據(jù)庫(kù)資源又是個(gè)瓶頸,不易橫向擴(kuò)展。所以在數(shù)據(jù)量大的時(shí)候,我們會(huì)采用單表查詢,把循環(huán)和匹配等大量工作移到應(yīng)用服務(wù)器上。應(yīng)用服務(wù)器容易擴(kuò)展,對(duì)并發(fā)支持更好。
當(dāng)數(shù)據(jù)量大到千萬(wàn)級(jí)以上,就建議盡可能減少join,鼓勵(lì)使用單表查詢。查詢優(yōu)化比較容易。這時(shí)候使用join的一個(gè)大型查詢就可能花很久,對(duì)其他查詢?cè)斐勺枞瑢?dǎo)致服務(wù)不可用。
當(dāng)考慮單表查詢后,就會(huì)衍生一系列的策略,比如冷熱數(shù)據(jù)分離,將熱數(shù)據(jù)和歷史數(shù)據(jù)分離,大幅降低數(shù)據(jù)量級(jí)以提高熱數(shù)據(jù)查詢性能,并可以使用內(nèi)存緩存。這樣又促使你考慮引入微服務(wù)架構(gòu)。
總結(jié),數(shù)據(jù)量小,查詢并發(fā)少,那么使用join的性能是可控的,開發(fā)成本低。當(dāng)數(shù)量級(jí)上升到千萬(wàn)級(jí)且不斷增加,盡早考慮向單表查詢切換,否則可能有性能下降會(huì)導(dǎo)致系統(tǒng)奔潰。而且性能下降不是線性的,會(huì)陡降。
0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答