mysql大數據量的大表分頁優化,按照時間字段排序,該字段有重複值,同時與主鍵id排序不一致.

當表達到幾十萬條時, 使用limit語句分頁查詢將會出現問題.查詢比較靠前的數據還好,但要是比較靠後的數據就會出現變得非常慢. 

需求: 有一個上百萬行的大表, 需要按照其時間字段順序分頁讀取, 該字段的順序與主鍵id順序並不一致. 而且該字段會有重複. 對於大表的分頁網上方法是按照主鍵id順序分頁, 所以可以利用到主鍵id的遞增特性達到效果: 如下面演示:

select * from table_name order by id asc limit 500000,10; //普通分頁語句

//轉換後的, 該語句查詢非常快
select * from table_name where id > (select id from table_name order by id asc limit 500000,10) limit 10

   但是本需求中, 顯然無法利用這個特性, 因其有重複值. 

 

解決方案: 

  1. 首先肯定是先對時間字段(假設該字段名爲create_time)加上索引了, 加上索引後limit 0,10這種查詢靠前的語句就非常快, 但是limit 500000,10語句這種查詢靠後數據的查詢就慢得令人髮指, 一般需要好幾秒. explain查詢計劃可以看到limit 50000.10這個語句mysql要先掃描前500000行後才能讀到數據,所以這就非常慢了.
  2. 在步驟1上繼續優化. 
    //對於幾十萬表基本都能在1s內查出來
    select * from table_name where id in (SELECT id from (select id from table_name LIMIT 500000,10) as tmp)  
    
    // 1.其中使用(SELECT id from (select id from table_name LIMIT 500000,10) as tmp)
         這種繁瑣的寫法是爲了適應mysql5.6不支持子查詢語句中有limit操作.當然你也可以將上述語句拆分成
         兩條,先執行子查詢獲取id結果集, 然後在用id in id結果集語句獲取最終結果也可.
    // 2.該句子主要時間花費在(SELECT id from (select id from table_name LIMIT 500000,10) as tmp) 
         子查詢上, 而 id in的查詢是非常快的,自己測試只要零點零幾秒. 
    
    // 3.最後要強調的是以上例子寫法比較簡化,查詢只取出自己需要的列,不要列就不要取出,因爲取出不需要的列
         時,傳送數據的時間會加大以及其他的一些開銷,尤其是無用的列很多很大時. 所以select *寫法要根據你
         的業務需要調整,有時候這個方面的耗時還是很大的,一定引起重視.

     

   錦上添花的解決方案(利用mysql本身的查詢緩存, 可只針對某些語句緩存)

    使用條件: (首先要是已經正在使用mysql查詢緩存,那麼這部分就可不看了)如果你要優化的這個查詢語句基本上是不變的, 例如你應用的一些公共數據(如首頁), 那麼這些只需要查詢一遍緩存起來,後續相同的查詢就可以直接使用,這樣速度是非常快的. 正好mysql是提供了查詢緩存這個功能, 什麼?你只要緩存一些特定的語句, 不想因優化一條語句而整個應用的所有語句都用上查詢緩存, 要知道查詢也是有開銷的, 對於一些語句是沒有幫助甚至會使其變慢. 湊巧, mqsql也支持只對指定的語句進行緩存其他語句不受影響.

    mysql的查詢緩存初步瞭解:  

 mysql的查詢緩存功能由query_cache_type系統變量控制,有如下取值:
   OFF:表示不開啓查詢
   ON: 表示對所有語句都開啓查詢緩存, 除非sql語句以SELECT SQL_NO_CACHE開頭明確表示不對該句子緩存
   DEMAND: 當語句以select SQL_CACHE開頭的纔會緩存

     代碼實現

1.找到你的mysql配置文件在 [mysqld] 塊下添加以下內容
  [mysqld]
  query_cache_type=2
  
2. 然後重啓你的mysql服務, 進入mysql命令行,執行如下命令
   show variables like "query_cache_type"; //再次確認下查詢緩存是否開啓
   show variables like "query_cache_size"; //確認查詢緩存大小,注意需要大於0
   set global query_cache_size = 1048576 //設置查詢緩存大小,可設置的值爲1024倍數(單位byte)需要大於40k
3. 對於你要緩存的select語句使用 SELECT SQL_CACHE開頭, 以下舉個栗子:
   SELECT SQL_CACHE * from table_name order by create_time desc limit 50000, 10;
   當mysql看到SELECT SQL_CACHE開頭時會去查詢緩存中找有沒有緩存過,沒有則執行語句並將結果緩存起來以供後續相同的查詢使用.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章