天天看點

mysql limit性能問題

來看一條sql:

SELECT m_id ,is_tax_paid FROM merchandise WHERE m_id > 10 AND last_update_time < NOW() ORDER BY m_id LIMIT (pageNum-1) * pageSize,pageSize
           

 merchandise表的m_id和last_update_time都加了唯一索引,當然,這裡不是組合索引。

初一看,這條sql沒有任何問題,但線上上跑了一陣子之後,有嚴重的性能問題,單次查詢要3秒左右,被記錄成慢sql。

原因是merchandise表太大,線上有1億多行資料,當頁數太多的時候,mysql的limit分頁要檢索的資料太多了,具體要看下mysql的B+樹索引是怎樣查資料的。

知道原因了,改進的方法,隻需要按id來分頁,每次查詢的時候,指定id的大小,然後再limit,如:

SELECT m_id ,is_tax_paid  FROM merchandise WHERE m_id > ? AND last_update_time < ? ORDER BY m_id LIMIT pageSize
           

每次循環的時候從查出的結果裡找到最大的m_id,把它傳給下次的sql查詢。上面的 m_id最好是唯一索引,主鍵索引,最好。

long updateBeginMid = 19541094l;
		while (true) {
			List<MerchandiseIsTaxPaid> midIsTaxPaidPairs = vipGoodsDao.listMidByLastUpdateTime(lastMigrateUpdateTime,updateBeginMid, BATCH_SIZE);
			doSomething(midIsTaxPaidPairs);
			if (CollectionUtils.isEmpty(midIsTaxPaidPairs) || midIsTaxPaidPairs.size() < BATCH_SIZE) {
				break;
			} else {
				int size = midIsTaxPaidPairs.size(); 
				MerchandiseIsTaxPaid merchandiseIsTaxPaid = midIsTaxPaidPairs.get(size - 1);
				updateBeginMid = merchandiseIsTaxPaid.getMerchandiseNo();	// 每次查詢從最大的更新id開始查起
			}
		}
           

 也可以參考這裡:

http://database.51cto.com/art/201005/200395.htm