MySQL两千万数据优化&迁移

最近有一张2000W条记录的数据表需要优化和迁移。2000W数据对于MySQL来说很尴尬,因为合理的创建索引速度还是挺快的,再怎么优化速度也得不到多大提升。不过这些数据有大量的冗余字段和错误信息,极不方便做统计和分析。所以我需要创建一张新表,把旧表中的数据一条一条取出来优化后放回新表;

一. 清除冗余数据,优化字段结构

2000W数据中,能作为查询条件的字段我们是预知的。所以将这部分数据单独创建新的字段,对于有规则的数据合理改变字段结构,比如身份证就是varchar(18)。对于不重要的数据我们合并后存在一个结构为text的字段。

对于一些有关联的数据我们需要计算,常见的比如身份证种能获取到准确的性别,出生地、生日、年龄。

二. 数据迁移

我们从数据库中取出一条旧数据,再通过计算处理后得到想要的新数据,最后将新数据插入新表。不过在获取新数据时遇到如下问题。

  1. 数据量太大,无法一次获取(2000W数据扔到内存挺可怕的);

    我们可以通过MySQL的limit语法分批获取。比如每次获取50000,SQL语句如下:

    select * from table_name limit 15000000,50000;
    

    通过这种方法能解决数据量太大的问题,但是随着limit的第一个参数越来越大,查询速度会慢的吓人(上面这条SQL执行会花35秒)。时间就是生命,于是我们开始优化SQL语句,优化后变成下面这样:

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

    可通过二分法拆分2000W数据,当执行到1000W数据时,将数据倒序。优化后SQL执行效率显著提升,从35秒降到9秒;

    不过还是很慢,时间就是生命……还好我们有自增ID(创建数据表第一条定律,一定要有自增字段),优化后的SQl如下:

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

    为了直观演示,我写了两条功能一样的SQL。相比第一条,第二条的limit会导致SQL的索引命中变差,效率同样也会下降。第一条SQL的执行时间是2毫秒,第二条执行时间5毫秒(我取的平均值)。每次数据的查询速度直接从35秒降到2毫秒……

  2. 数据量太大并且数据无法预估,某些特殊数据会导致数据导入失败;

    我们有三种方案去将新数据存入新表,分别如下:

    1. 一条一条插入数据;

      开始肯定会想这种方案一定不行,因为每次插入都会有一次数据库IO操作。但是该方案有个好处是能及时发现有问题的数据,修改后再继续执行; 在Oracle中使用『绑定变量』能带来性能提升,正好MySQL也提供了『绑定变量』的功能。于是在不改变逻辑的情况下,尝试优化数据存储速度。代码如下:

      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();
      }
      

      最后效果不怎么好,MySQL的『绑定变量』并没带来明显的速度提升,不过能有效的防止SQL注入;

    2. 一次插入50000条数据;

      这是我最后选中的方案,一是能及时发现有问题的数据,二是导入数据非常稳定。就像支持断点续传一样,每一步都能看到效果。在执行脚本时,也能同步开始写分析逻辑;

    3. 组装成SQL文件,最后统一导入;

      组装一个大的SQL文件,最后通过MySQL自带的工具导入也是极好的。但如果有一条SQL有问题,你可能需要重跑一次脚本。因为在9G大小的文本文件中修改一个符号是很痛苦的事情……

三. 总结

通过各种优化,最后将脚本执行时间缩短到了20分钟内。优化后数据质量得到了较高保证,下次将尝试2亿数据的优化&迁移……

PS:原文地址 http://blog.it2048.cn/article_2000w-data.html 之后我会陆续把自己博客迁移到,希望大家关注!

时间: 2024-12-21 20:32:04

MySQL两千万数据优化&迁移的相关文章

Mysql数据库千万数据修改迁移问题

问题描述 Mysql数据库千万数据修改迁移问题 5C 环境:数据库DATA中有三张表分别为 表A.表B.表C 需求:表A中有1200万数据,现在需要将表A中的部分字段数据插入表B中,将表A中剩余部分字段插入表C中,在插入过程中,会对字段数据进行部分处理(如某字段为空,则随机插入写那些).问题: 除了查出表A中的数据然后一条一条处理插入还有什么好的方式能优化效率呢!! 解决方案 MySQL数据库数据位置迁移 解决方案二: 还不是一样用SQL语句啊 解决方案三: 事务应该可以吧,但效率好像不好说 解

mysql两表数据匹配,更新结果为什么为0

问题描述 mysql两表数据匹配,更新结果为什么为0 update crm_customerhr_postset crm_customer.beseats_depid=hr_post.dep_idcrm_customer.beseats_depname=hr_post.depnamewhere hr_post.emp_id=crm_customer.BeSeats 解决方案 0就是没有数据更新呗,没有符合条件的数据吧 解决方案二: 字段名合适的没?表里边有没有这些字段

MySQL写入插入数据优化配置

*innodb_buffer_pool_size 如果用Innodb,那么这是一个重要变量.相对于MyISAM来说,Innodb对于buffer size更敏感.MySIAM可能对于大数据量使用默认的key_buffer_size也还好,但Innodb在大数据量时用默认值就感觉在爬了. Innodb的缓冲池会缓存数据和索引,所以不需要给系统的缓存留空间,如果只用Innodb,可以把这个值设为内存的70%-80%.和 key_buffer相同,如果数据量比较小也不怎么增加,那么不要把这个值设太高也

mysql两表数据全表复制方法

声名:a,b ,都是表--b表存在(两表结构一样) insert into b select * from a若两表只是有部分(字段)相同,则insert into b(col1,col2,col3,col4,...) select col1,col2,col3,col4,... from a where...把表a插入到表b中去. --b表不存在 select * into b from a //select (字段1,字段2,...) into b from a

mysql 插入10万条数据 优化效率

问题描述 mysql 插入10万条数据 优化效率 public int addTypes(List<taobaoBean> babyList) { String sql = "insert into type (typeid,url) values (?,?) "; Connection conn = dbhelper.getConnection(driver,url,username,upwd); int result = 0; PreparedStatement stm

对网上盛传的两千万泄漏数据的简单分析

最近网上盛传两千万酒店用户数据泄漏,出于好奇,我也从网上下载了一份下来.本次下载纯粹是出于学习和研究用,不会做什么坏事,不要问本人要下载地址,大家自己找.由于本人并不是学统计和数据挖掘方面的,所以只能浅显的做做统计分析,下面开始我们的学习和研究. 首先,数据源只有一个表(总数据2005W),里面主要存放了用户的姓名.证件类型,证件号码,生日,性别,住址,手机号码,邮箱等私人信息.这些数据应该是从多个数据源集成进来的,因为里面的格式很不工整,有些默认值使用的也不一样.我们要做数据分析,那么需要进行

mysql 数据库-mysql问题:从三个表查询数据优化

问题描述 mysql问题:从三个表查询数据优化 我有三个表,三个表的数据全部查询出来再排序,三个表的数据都很大,如何查询才能最节省资源,最优. 解决方案 可以建一个视图,把你经常要用到的字段放入视图中,当然和你的查询语句也有关系 解决方案二: 楼上说的建视图,有点换汤不换药吧! 大数据量查询,建议去看看索引方面的东西吧

数据库迁移-请DBA大神进,有关千万数据迁移的问题。

问题描述 请DBA大神进,有关千万数据迁移的问题. 公司最近有个需求 ,需要将一张老系统数据里某张表大概4000万数据迁移到新系统中,迁移过程中还需要对老表中的字段特殊处理以后再插入新表.而且老数据库表有分表,新系统也建立对应分表迁移. 我是这样做的 用了3个存储过程,入口调用另外2个那样 1.根据老系统中规则 在新系统中创建好分表. 2.将老系统中分表的数据插入到新系统中对应的分表. 3.老系统未分表的数据插入新系统中. 做了测试,存储过程逻辑是没有问题的,现在的担心是性能瓶颈问题, 整个采取

mysql 通过拷贝数据文件的方式进行数据库迁移实例_Mysql

mysql通过拷贝数据文件的方式进行数据库迁移 --环境windows 将源机器A数据库拷贝到目标机器B: 我先在目标机器B上安装MySQL,停止mysql服务,然后将源机器A的data下关于数据库的文件和ibdata1拷贝过去,其余不用拷贝.如图: 源机器A: 启动目标数据库服务net start mysql,即可查看到导过来的所有数据库了. 注意:ibdata1一定不要忘记拷贝,且要拷贝到准确的位置(如我目标机器的ibdata1在E:\MySQL Datafiles,不在data路径下,我就