今天做一個業務需求的邏輯處理,需要對MySQL全表進行遍歷,數據規模百萬級別,為方便描述,這張表就用 a 來代替吧
結合自己的思路和一些資料,在這里記錄一下方案的進化史
一、直接遍歷拿出所有的數據
select * from a ;
這個肯定不用多說了,估計還沒拿完,內存就爆了,對這種數量級的表不現實
二、分頁式循環遍歷
select * from a limit 0,1000; select * from a limit 1000,1000。
在代碼中,循環地使用這種模式的sql去遍歷表,雖然可以實現,但顯然這種方式是沒法用到索引,越往后遍歷性能會越低。
三、帶索引鏈式遍歷
select * from a where id > 0 order by id limit 10000;
假設上一次查詢得到的結果集中,最后一條數據的id為10001 select * from a where id > 10001 order by id limit 10000;
好,既然沒用到索引,那就帶上索引遍歷。
類似的查詢效果,由於where條件中的id字段有索引,對於比較靠后的數據,查詢性能將會輕松提升很多(有人說是百倍左右,我沒測試過就不說具體多少了)
那初步的優化方案就很容易想到了,id有索引,而且是自增的,就從id=1開始遍歷,結果集以id升序排列,然后根據結果集最后一條數據的id,繼續下一次遍歷,依此類推,直到遍歷完成
這個方案有個特點:下次遍歷必須知道上次遍歷的最后一個id的值,也就是前后遍歷形成了一個依賴鏈,這將導致無法實現遍歷行為之間的並行操作
四、id分區多線程遍歷
找到表中最大最小id,確定id區間 select min(id),max(id) from a ; 多線程遍歷,每個線程每批次拿10000條記錄,從min(id)開始,到max(id)結束 線程1: select * from a where id >= 1 and id <= 10000; 線程2: select * from a where id >= 100001 and id <=20000;
那如果我想多線程並行SQL查詢處理呢?那我們可以嘗試進行ID的區間划分,因為有了ID的分區,各個分區的查詢就不存在必要的關聯性了。
比如,第一個線程遍歷id區間為1-10000的數據,第二個線程遍歷id區間為10001-20000的數據,依此類推,直到遍歷到最大id。這樣就可以實現多個線程並行操作,性能也許會大大提升。
但不能說方案四一定比方案三好,要根據實際情況進行選擇。方案四需要考慮ID的區間大小和SQL並行查詢的線程數(數據庫壓力)。
而對於存儲過程或游標之類,個人認為移植性和通用性不是很好,就沒研究那方面的。
先寫到這里,后續有什么好的方案,再補上!
參考:
共同學習,共同進步,若有補充,歡迎指出,謝謝!
