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

相关文章
相关标签/搜索