2019/4/9 8:18:23
我們要訪問的(de)表是一個(gè)非常大(dà)的(de)表,四千萬條記錄,id是主鍵,program_id上(shàng)建了索引。
執行(xíng)一條SQL:
select * from program_access_log where program_id between 1 and 4000
這條SQL非常慢(màn)。
我們原以爲處理(lǐ)記錄太多的(de)原因,所以加了id限制(zhì),一次隻讀(dú)五十萬條記錄
select * from program_access_log where id between 1 and 500000 and program_id between 1 and 4000
但(dàn)是這條SQL仍然很慢(màn),速度比上(shàng)面一條幾乎沒有(yǒu)提升。
Mysql處理(lǐ)50萬條記錄的(de)表,條件(jiàn)字段還建了索引,這條語句應該是瞬間完成的(de)。
問題分(fēn)析:
這張表大(dà)約容量30G,數據庫服務器(qì)内存16G,無法一次載入。就是這個(gè)造成了問題。
這條SQL有(yǒu)兩個(gè)條件(jiàn),ID一到(dào)五十萬和(hé)Program_id一到(dào)四千,因爲program_id範圍小(xiǎo)得多,mysql選擇它做爲主要索引。
先通過索引文(wén)件(jiàn)找出了所有(yǒu)program_id在1到(dào)4000範圍裏所有(yǒu)的(de)id,這個(gè)過程非常快。
接下來要通過這些id找出表裏的(de)記錄,由于這些id是離(lí)散的(de),所以mysql對這個(gè)表的(de)訪問不是順序讀(dú)取。
而這個(gè)表又(yòu)非常大(dà),無法一次裝入内存,所以每訪問一條記錄mysql都(dōu)要重新在磁盤上(shàng)定位并把附近的(de)記錄都(dōu)載入内存,大(dà)量的(de)IO操作導緻了速度的(de)下降。
問題解決方案:
1. 以program_id爲條件(jiàn)對表進行(xíng)分(fēn)區
2. 分(fēn)表處理(lǐ),每張表的(de)大(dà)小(xiǎo)不超過内存的(de)大(dà)小(xiǎo)
然而,服務器(qì)用(yòng)的(de)是mysql5.0,不支持分(fēn)區,而且這個(gè)表是公共表,無法在不影響其它項目的(de)條件(jiàn)下修改表的(de)結構。
所以我們采取了第三種辦法:
select * from program_access_log where id between 1 and 500000 and program_id between 1 and 15000000
現在program_id的(de)範圍遠大(dà)于id的(de)範圍,id被當做主要索引進行(xíng)查找,由于id是主鍵,所以查找的(de)是連續50萬條記錄,速度和(hé)訪問一個(gè)50萬條記錄的(de)表基本一樣
總結:
這是一個(gè)在千萬筆(bǐ)記錄表中由于使用(yòng)了索引導緻了數據查找變慢(màn)的(de)問題,有(yǒu)一定的(de)典型性和(hé)大(dà)家交流下!
深圳市南山區南山街(jiē)道南海(hǎi)大(dà)道西(xī)桂廟路(lù)北陽光(guāng)華藝大(dà)廈1棟4F、4G-04
咨詢電話(huà):136 8237 6272
大(dà)客戶咨詢:139 0290 5075
業(yè)務QQ:195006118
技術(shù)QQ:179981967