問題描述:
我們要訪問的表是一個非常大的表,四千萬條記錄,id是主鍵,program_id上建瞭索引。
執行一條SQL:
select * from program_access_log where program_id between 1 and 4000
這條SQL非常慢。
我們原以為處理記錄太多的原因,所以加瞭id限制,一次隻讀五十萬條記錄
select * from program_access_log where id between 1 and 500000 and program_id between 1 and 4000
但是這條SQL仍然很慢,速度比上面一條幾乎沒有提升。
Mysql處理50萬條記錄的表,條件字段還建瞭索引,這條語句應該是瞬間完成的。
問題分析:
這張表大約容量30G,數據庫服務器內存16G,無法一次載入。就是這個造成瞭問題。
這條SQL有兩個條件,ID一到五十萬和Program_id一到四千,因為program_id范圍小得多,mysql選擇它做為主要索引。
先通過索引文件找出瞭所有program_id在1到4000范圍裡所有的id,這個過程非常快。
接下來要通過這些id找出表裡的記錄,由於這些id是離散的,所以mysql對這個表的訪問不是順序讀取。
而這個表又非常大,無法一次裝入內存,所以每訪問一條記錄mysql都要重新在磁盤上定位並把附近的記錄都載入內存,大量的IO操作導致瞭速度的下降。
問題解決方案:
1. 以program_id為條件對表進行分區
2. 分表處理,每張表的大小不超過內存的大小
然而,服務器用的是mysql5.0,不支持分區,而且這個表是公共表,無法在不影響其它項目的條件下修改表的結構。
所以我們采取瞭第三種辦法:
select * from program_access_log where id between 1 and 500000 and program_id between 1 and 15000000
現在program_id的范圍遠大於id的范圍,id被當做主要索引進行查找,由於id是主鍵,所以查找的是連續50萬條記錄,速度和訪問一個50萬條記錄的表基本一樣
總結:
這是一個在千萬筆記錄表中由於使用瞭索引導致瞭數據查找變慢的問題,有一定的典型性和大傢交流下!