千萬級資料庫使用索引查詢速度更慢的疑惑-資料回表問題
-
環境
-
資料庫:TiDB資料庫(和mysql資料庫極其相似的資料庫)
-
表名:index_basedata
-
表資料:13 000 000條資料
-
表索引:包含一個普通索引,索引列 ”year“
-
測試sql:
-
SQL1 : select brand from index_basedata where year = 2018 group by day limit 5;
-
SQL2 : select brand from index_basedata where month = 201807 group by day limit 5;
-
SQL3 : select brand from index_basedata where year = 2018 limit 5;
-
SQL4 : select brand from index_basedata where month = 201807 limit 5;
-
sql1與sql2對比 , sql3與sql4對比
-
-
-
問題
-
測試sql執行時間:
-
SQL1 : 23.6s
-
SQL2 : 4.5s
-
SQL3 : 0.007s
-
SQL4 : 1.4s
-
-
explain解釋: 瞭解TiDB資料庫相關與explain請移步:https://pingcap.com/docs-cn/overview/#tidb-%e6%95%b4%e4%bd%93%e6%9e%b6%e6%9e%84
-
sql1:select brand from xcar_index_basedata_noprice where year = 2018 group by day limit 5;
-
sql2:select brand from xcar_index_basedata_noprice where month = 201807 group by day limit 5;
-
sql3:select brand from xcar_index_basedata_noprice where year = 2018 limit 5;
-
sql4:select brand from xcar_index_basedata_noprice where month = 201807 limit 5;
-
-
從圖中可以看出,sql1和sql3使用了索引,sql2和sql4沒有使用索引。
-
對於sql1和sql2,本應該使用所以的查詢時間少,但是使用了索引的sql1使用的時間是沒有使用索引的sql2查詢時間的5倍,為什麼?
-
對於sql3和sql4,恢復了正常,使用索引比不使用索引查詢速度快,為什麼上述兩個現象會相差如此之大?
-
-
解答(以下為個人理解,不同理解請不吝指教)
-
在sql1和sql2中,sql1索引列獲取資料的速度大於sql2中獲得資料的速度。但是在group by時在sql1中,使用索引得到的地址,需要回表才可以得到真實的資料,需要根據地址去獲取資料,資料回表問題嚴重。
-
在sql2中獲取的是直接資料,group by 不需要回表。
-
sql2,sql3,sql4表現正常。
-
-
什麼是回表?
-
通俗的講:如果索引的列在select所需獲得列中就不需要回表(因為在mysql中索引是根據索引列的值進行排序的,所以索引節點中存在該列中的部分值),如果select所需獲得列中有大量的非索引列,索引就需要到表中找到相應的列的資訊,這就叫回表。
-
案例:
-
測試環境:與上述相同
-
測試sql:
-
sql1:select brand from index_basedata where year = 2018 group by day limit 5;
-
執行時間:21.8s
-
explain一下:
-
使用了索引“year”, 則索引列為year,但是select brand from..中brand並不是索引列,就需要回表(通過圖也可以看出,進行了tablescan,另外其中的IndexLookUp也說明了進行了回表),所以花費時間長
-
sql2:select brand from index_basedata where year = 2018 group by year limit 5;
-
執行時間:21.7s
-
explain一下:
-
使用了索引“year”, 則索引列為year,但是select brand from..中brand並不是索引列,就需要回表(通過圖也可以看出,進行了tablescan,另外其中的IndexLookUp也說明了進行了回表),所以花費時間長,另外,對於sql2中的group by使用的是索引列,所以使用的StreamAgg,不同於sql1
-
sql3:select year from index_basedata where year = 2018 group by year limit 5;
-
執行時間:2.5s
-
explain一下:
-
可以看到:沒有tablescan,也沒有使用IndexLookUp而是IndexReader說明直接從索引中讀取索引列並使用。
-
-
總結:在上述案例中,sql3使用了索引列,沒有進行回表,sql1與sql2進行了回表,所以花費時間長。所以說,發生嚴重的回表的時候,查詢速度比不使用索引還慢。
-
-
那麼,下面的5個sql執行時間能不能理解呢?
-
select year from xcar_index_basedata_noprice where year = 2018 group by year limit 5;
-
select month from xcar_index_basedata_noprice where month = 201807 group by month limit 5
-
select brand_id from xcar_index_basedata_noprice where month = 201807 group by month limit 5;
-
select brand_id from xcar_index_basedata_noprice where year = 2018 group by year limit 5;
-
select brand_id from xcar_index_basedata_noprice where year = 2018 group by month limit 5;
-
對應執行時間:
-
相關文章
- mysql千萬級資料量根據索引優化查詢速度MySql索引優化
- mysql千萬級資料量根據索引最佳化查詢速度MySql索引
- 資料庫表的唯一索引問題資料庫索引
- 比較有索引和無索引的查詢速度(在mysql資料庫中)索引MySql資料庫
- 併發查詢資料庫問題資料庫
- 緊急問題:我級聯資料表怎麼查資料庫有問題呢???資料庫
- QL Server 百萬級資料提高查詢速度的方法Server
- C語言連線mysql資料庫查詢中文的資料表亂碼問題C語言MySql資料庫
- MyBatis千萬級資料查詢解決方案,避免OOMMyBatisOOM
- 資料庫資料的查詢----連線查詢資料庫
- 資料庫基礎查詢--單表查詢資料庫
- 資料庫中單表查詢資料庫
- 【資料庫】sql連表查詢資料庫SQL
- 查詢資料庫表是否存在資料庫
- 使用閃回查詢備份資料
- 資料庫查詢和資料庫(MySQL)索引的最佳化建議資料庫MySql索引
- mysql 資料庫或者表空間使用查詢MySql資料庫
- 提高ORACLE資料庫的查詢統計速度(轉)Oracle資料庫
- 資料庫 - 資料查詢資料庫
- 在`Laravel`中使用`cursor`來查詢並處理資料 (輕鬆處理千萬級的資料)Laravel
- 在Laravel中使用cursor來查詢並處理資料 (輕鬆處理千萬級的資料)Laravel
- mysql 5.7後使用sys資料庫下的表查詢資料庫效能狀況MySql資料庫
- 回閃查詢查詢刪除的資料
- 資料庫索引分裂 問題分析資料庫索引
- 查詢Oracle資料庫使用者表中的多少資料量Oracle資料庫
- 查詢MySQL資料庫,MySQL表的大小MySql資料庫
- 上億級別資料庫查詢資料庫
- 千萬級MySQL資料庫建立索引,提高效能的祕訣MySql資料庫索引
- 資料庫分組查詢最大值的問題資料庫
- 關於下拉選單查詢資料庫的問題資料庫
- (利用索引)大資料查詢索引大資料
- Oracle資料庫的閃回查詢功能簡介Oracle資料庫
- 資料庫升級到mysql5.6遇到的資料表ENGINE問題資料庫MySql
- AppBoxFuture: 二級索引及索引掃描查詢資料APP索引
- 資料庫索引層級資料庫索引
- 資料庫查詢資料庫
- 使用cglib實現資料庫框架的級聯查詢CGLib資料庫框架
- 資料庫系列:覆蓋索引和規避回表資料庫索引