關於mysql的幾個問題,公司中實際遇到的,請大神給看一下,大家討論一下?
有二大塊問題:
一:我有一張1G的表,要全部讀出來,假如我的mysql內存只有512M,請問這種情況是否會造成mysql因為內存不足而死機?當內存不足時,mysql是否有相應的處理機制? 而且這些數據我還要讀到應用伺服器(比如 apache),那麼應用伺服器是否也會存在內存不足而死機的問題?
二:有三張表相互join,比如 a join b join c on a.id=b.id and a.id=c,id。 mysql的處理步驟應該是先join兩張表,把結果最後再與第三張表join。不考慮索引,這個處理過程中,mysql的內存中應該不會同時存在三張表的數據吧?我的理解是:比如a和b的join的結果集,再與C表join,怎麼也不會超過三張表。是否是這樣?
而因為三張表都非常大,處理起來也比較複雜,現在呢我們公司是想這麼做,有兩種方案:
第一方案:使用定時任務,在夜間,把a,b,c三張表直接join取出結果存儲成一個最終表,最後應用直接去讀這個最終表即可。
第二種方案:分開處理,使用定時任務,先把a join b 的結果集放存儲成一個基表1,另一個定時任務再把這個基表1與c表進行join,得到一個最終表。那麼這兩種方案哪個更合適?
我的理解是,無論你分開不分開,貌似都是一樣的,還不如第一種直接都join得出最終表方便。假如說第二種方案中,兩個定時任務銜接的很好,依次去處理,站在內存的角度去想,這與第一種方案所持續占的內存應該是一樣的吧,CPU的使用率也是一樣的吧。你們怎麼理解呢?
第一個問題:如果你的讀取數據的SQL只是掃描表,不包含group by或者order by這樣需要物化(打斷流水)的操作,是不會導致內存不足的,資料庫內部的掃描是流式操作,得到的是一個row iterator,返回給客戶端的數據是通過若干個數據包返回的,最大長度16M,一個包返回了,需要下一個包,才會取一批row,所以內存不用擔心,客戶端我對jdbc不是很熟悉,貌似jdbc也不會一次性將這麼多數據全部load到jvm內存中,客戶端對於result set也是維護了一個cursor,有對應的fetch size,一次fetch一部分數據,如果驅動cursor繼續迭代,再獲取一批。問題二:MySQL只支持nested loop join和merge join,貌似在MySQL 8實現了hash join(記不太清楚了)三張表數據都很大,並且如果每張表上都沒有太強的filter,優化器應該不會選擇nested loop join,IO代價太高了,很大可能是選擇merge join,其實對於大表的join最好的是hash join,具體選擇什麼join方式,最好explai看一下,不管什麼join,只要都是inner join,資料庫內部都是左深樹,會先連接兩張表得到的結果再跟地三張表連接,merge join的話,如果連接鍵上沒有序,就需要排序,這麼大數據量內排的內存太小,需要外排,外排需要寫排序文件,性能不會太好,所以最好是能在連接鍵上建索引,避免排序,第二種方案和第一種方案就join本身的計算不會有什麼不同,而且還多了一個寫中間結果表的過程,需要將數據拉回客戶端,再寫回資料庫,多了額外的CPU,內存和網路的消耗,寫數據還有事務的消耗,從這個角度來說不划算。但可能這種方式能夠提前將第一張表和第二張表join消耗的資源先釋放,是一個好處,所以嚴格來說說不清誰更好,但就一般經驗來看,弊大於利。
所以我的建議是用第一個方案,直接join三張表的結果,處理也更簡單,在連接鍵上加索引,或者是主鍵,避免join排序。
既然是實際業務問題,而不是面試/演算法問題……
那我真的不是太理解,讀取1G數據的理由了……
問題一:肯定是分批讀
問題二:不管怎麼歸檔,內存方面還是要分批讀。肯定要用索引,不在乎索引磁碟io比較多,語句很慢
工作中勤于思考是好事,但是.....
你提到的問題可以從任何一個學校的本科的資料庫課程中找到答案好嘛!!!!!
我覺得你最好去看一下資料庫系統概念這本書,而不是到知乎上提問~~
第一個問題:請看第十章,它會告訴你關係型資料庫為什麼設計成磁碟存儲模式而不是內存模式
第二個問題:請看十二章第5節,它會告訴你資料庫連接是怎麼通過三大嵌套兩大連接實現的,看完後你自然會知道中間結果是怎麼存儲的~
其他回答基本從原理和了解原理回答了。
我只想問:
0、需求真的需要把數據全部讀出來么?
1、如果是,為什麼沒有做實驗試試呢?
我來學習的。。。。。。。。。。
如果是用來分析的話,1G的表全量導也沒多久吧。。。如果是實際業務的話,要思考下這個業務是否合理了。。。
mysql會生成臨時文件。。。1G的數據量真的不大,現在好一點的伺服器內存都是512G的。。。如果索引得當,連接操作會走索引,而不是全表掃描。
第一個問題,數據過大只會造成佔用過多的資源造成別的session運行速度降低,不會死機,如果因此而死機了,那麼這不是你的問題,是MySQL的問題。第二個問題,SQL的優化向來都是細節取勝,看似複雜的問題其實瓶頸只是在一處,一個看似微不足道的更改會影響全局的效率,你在執行SQL的時候應該解釋一下,具體看看是哪步出了問題,是不是要調整什麼參數。或者從邏輯上過濾沒必要的連接和io。應用一些策略,比如小集合驅動大集合什麼的,你這樣在知乎上泛泛的提問即使別人告訴你一個可行的思路你自己去實現的話也變味了。
首先你是什麼日誌?,什麼表?,innodb表的話我建議你在資料庫中定義一個專門的表在低負載時間裡保存查詢結果。我支持方案一
推薦閱讀:
※如何理解資料庫事務中的一致性的概念?
※如何設計一個資料庫,能夠存下如此「大量」的數據?
※MySQL 查詢 select * from table where id in (幾百或幾千個 id) 如何提高效率?
※uuid作為主鍵,還是用自增呢?