MySQL兩千萬數據優化&遷移

最近有一張2000W條記錄的數據表須要優化和遷移。2000W數據對於MySQL來講很尷尬,由於合理的建立索引速度仍是挺快的,再怎麼優化速度也得不到多大提高。不過這些數據有大量的冗餘字段和錯誤信息,極不方便作統計和分析。因此我須要建立一張新表,把舊錶中的數據一條一條取出來優化後放回新表;html

一. 清除冗餘數據,優化字段結構mysql

2000W數據中,能做爲查詢條件的字段咱們是預知的。因此將這部分數據單首創建新的字段,對於有規則的數據合理改變字段結構,好比身份證就是varchar(18)。對於不重要的數據咱們合併後存在一個結構爲text的字段。sql

對於一些有關聯的數據咱們須要計算,常見的好比身份證種能獲取到準確的性別,出生地、生日、年齡。數據庫

二. 數據遷移ide

咱們從數據庫中取出一條舊數據,再經過計算處理後獲得想要的新數據,最後將新數據插入新表。不過在獲取新數據時遇到以下問題。工具

  1. 1. 數據量太大,沒法一次獲取(2000W數據扔到內存挺可怕的);性能

    咱們能夠經過MySQL的limit語法分批獲取。好比每次獲取50000,SQL語句以下:優化

    SQLspa

    select * from table_name limit 15000000,50000;

    SQLcode

    Copy

    經過這種方法能解決數據量太大的問題,可是隨着limit的第一個參數愈來愈大,查詢速度會慢的嚇人(上面這條SQL執行會花35秒)。時間就是生命,因而咱們開始優化SQL語句,優化後變成下面這樣:

    SQL

    select * from table_name order by id desc limit 5000000,50000;

    SQL

    Copy

    可經過二分法拆分2000W數據,當執行到1000W數據時,將數據倒序。優化後SQL執行效率顯著提高,從35秒降到9秒;

    不過仍是很慢,時間就是生命……還好咱們有自增ID(建立數據表第一條定律,必定要有自增字段),優化後的SQl以下:

    SQL

    1. select * from table_name where id>15000000 and id<15050000;
    2. select * from table_name where id>15000000 limit 50000;

    SQL

    Copy

    爲了直觀演示,我寫了兩條功能同樣的SQL。相比第一條,第二條的limit會致使SQL的索引命中變差,效率一樣也會降低。第一條SQL的執行時間是2毫秒,第二條執行時間5毫秒(我取的平均值)。每次數據的查詢速度直接從35秒降到2毫秒……

  2. 2. 數據量太大而且數據沒法預估,某些特殊數據會致使數據導入失敗;

    咱們有三種方案去將新數據存入新表,分別以下:

    1. 1. 一條一條插入數據;

      開始確定會想這種方案必定不行,由於每次插入都會有一次數據庫IO操做。可是該方案有個好處是能及時發現有問題的數據,修改後再繼續執行; 在Oracle中使用『綁定變量』能帶來性能提高,正好MySQL也提供了『綁定變量』的功能。因而在不改變邏輯的狀況下,嘗試優化數據存儲速度。代碼以下:

      PHP

      public function actionTest(array $data)
      {
          $mysqli = new mysqli("192.168.1.106", "username", "password", "test");
          $sql = "insert into table_name(name,identity) values (?,?)";
      
          $stmt = $connection->prepare($sql);
          $name = "";
          $identity = "";
          //使用綁定變量
          $stmt->bind_param("si", $name, $identity);
          foreach($data as $val)
          {
              $name = $val[name];
              $identity = $val[card_id];
              //執行
              $stmt->execute();
          }
          $stmt->close();
      }

      PHP

      Copy

      最後效果不怎麼好,MySQL的『綁定變量』並沒帶來明顯的速度提高,不過能有效的防止SQL注入;

    2. 2. 一次插入50000條數據;

      這是我最後選中的方案,一是能及時發現有問題的數據,二是導入數據很是穩定。就像支持斷點續傳同樣,每一步都能看到效果。在執行腳本時,也能同步開始寫分析邏輯;

    3. 3. 組裝成SQL文件,最後統一導入; 

      組裝一個大的SQL文件,最後經過MySQL自帶的工具導入也是極好的。但若是有一條SQL有問題,你可能須要重跑一次腳本。由於在9G大小的文本文件中修改一個符號是很痛苦的事情……

三. 總結

經過各類優化,最後將腳本執行時間縮短到了20分鐘內。優化後數據質量獲得了較高保證,下次將嘗試2億數據的優化&遷移……

做者: 極客導航(http://it2048.cn/)極客博客(http://blog.it2048.cn/)  文章地址: http://blog.it2048.cn/article_2000w-data.html

相關文章
相關標籤/搜索