zoukankan      html  css  js  c++  java
  • 41 快速的复制一张表

    41 快速的复制一张表

    create database db1;
    use db1;
    
    create table t(id int primary key, a int, b int, index(a))engine=innodb;
    delimiter ;;
      create procedure idata()
      begin
        declare i int;
        set i=1;
        while(i<=1000)do
          insert into t values(i,i,i);
          set i=i+1;
        end while;
      end;;
    delimiter ;
    call idata();
    
    create database db2;
    create table db2.t like db1.t

    现在把db1.t的数据a>800的数据行导入db2.t

    Mysqldump方法

    mysqldump -h127.0.0.1 -P3306 -usystem -p  --default-character-set=utf8 --no-create-info --single-transaction  --set-gtid-purged=OFF db1 t --where="a>800" --result-file=/tmp/t.sql

    把结果输出到临时文件

    -rw-rw-r--  1 mysql     mysql      4261 Mar 27 08:32 t.sql

    生成一个insert语句里面包含多个values对,用这个文件来写入的时候,执行速度可以更快。

    --skip-extended-insert 生成多个insert语句。

    导入db2

    mysql -h127.0.0.1 -P3306 -usystem -p  db2  -e "source /tmp/t.sql"
    (system@127.0.0.1:3306) [test]> select count(*) from db2.t;
    +----------+
    | count(*) |
    +----------+
    |      200 |
    +----------+

    说明,source并不是一条sql语句,而是一个客户端命令,mysql客户端执行命令的流程

    --1 打开文件,默认以分好为结尾读取一条条的sql语句

    --2 sql语句发送到服务端执行

    slow logbinlog中,并不会有source出现。

    导出csv文件

    select * from db1.t where a>800 into outfile '/data/mysqldata/loadfile/t.csv';

    导出的文件路径,参数限制secure_file_priv

    --如果设置为empty,表示不限制生成文件的位置,不安全的配置

    --设置为一个表示路径的字符串,要求生成的文件只能放在该路径的目录或者子目录

    --设置为null,表示禁止这个mysql实例上执行select 。。Into outfile操作。

    导入db2

    load data infile '/data/mysqldata/loadfile/t.csv' into table db2.t;

    执行流程

    --1 打开文件csv,以制表符( )作为字段间的分隔符,以换行符( )作为记录之间的分隔符,进行数据读取

    --2 启动事务

    --3 判断每一行的字段数与表db2.t是否相同

    ---若不相同,直接报错,事务回滚

    ---若相同,则构造成一行,调用innodb engine接口,写入到表中

    --4 重复步骤3,知道csv整个文件读入完成,提交事务。

    如果binlog_format=statement,这个load语句记录到binlog以后,备库怎么重放?

    由于csv文件只保存在主库所在的主机上,如果只把这个语句原文写到binlog中,备库在执行的时候,备库的服务器上没有这个文件,就会导致备库报错停止。

    所以,这条语句执行的完成流程

    --1 主库执行完成后,将csv文件的内容直接写到binlog文件中

    --2 binlog文件中写入语句load data local infile xx into table db2.t

    --3 把这个binlog日志传到备库

    --4 备库的apply线程在执行这个事务日志时

    --a 先将binlog中的t.csv文件的内容读出来,写到本地临时目录中

    --b 再执行load data语句,往备库的db2.t表中插入跟主库相同的数据。

    -load data中多了local将执行这条命令的客户端所在机器的本地文件/tmp/xx的内容,加载到目标表的db2.t”。

    也就是说,load data命令有两种用法

    --不加local,是读取服务端的文件,这个文件必须是secure_file_priv指定的路径下

    --local,读取的是客户端文件,只要mysql客户端有访问这个文件的权限,这时候,mysql客户端会先把本地文件传给服务端,然后执行load data

    另外注意select 。。。Into outfile方法不会生成表结构文件,所以在导出数据的时候要另外导出表结构,mysqldump提供 了-tab参数,可以同时导出csv数据文件和表结构定义文件。

    mysqldump -h$host -P$port -u$user ---single-transaction  --set-gtid-purged=OFF db1 t --where="a>900" --tab=$secure_file_priv

    物理拷贝方法

    直接把db1.tfrmidb文件拷贝到db2目录下,是不行的。

    Innodb表,除了物理文件外,还需要在数据字典中注册,直接拷贝的话,数据字典是不会识别的。

    mysql5.6引入了可传输表空间(transportable tablespace)方法,具体步骤

    --1 执行create table r like t;创建一个相同的表结构的表

    --2 执行alter table r discard tablespace 这是r.ibd文件会被删除

    --3 执行flush table t export,在db1目录下会生成一个t.cfg文件

    --4 db目录下执行cp t.cfg r.cfg;cp t.ibd r.idb(注意权限)

    --5 执行unlock tablest.cfg文件会删除

    --6 执行alter table r import tablespace,将这个r.idb文件作为表r的新的表空间

    (system@127.0.0.1:3306) [db1]> use db1
    Database changed
    (system@127.0.0.1:3306) [db1]> create table r like t;
    Query OK, 0 rows affected (0.06 sec)
    
    (system@127.0.0.1:3306) [db1]> system ls -l /data/mysqldata/3306/data/db1/r.*
    -rw-r----- 1 mysql mysql   8604 Mar 27 09:30 /data/mysqldata/3306/data/db1/r.frm
    -rw-r----- 1 mysql mysql 114688 Mar 27 09:30 /data/mysqldata/3306/data/db1/r.ibd
    (system@127.0.0.1:3306) [db1]> alter table r discard tablespace;
    Query OK, 0 rows affected (0.02 sec)
    
    (system@127.0.0.1:3306) [db1]> system ls -l /data/mysqldata/3306/data/db1/r.*
    -rw-r----- 1 mysql mysql 8604 Mar 27 09:30 /data/mysqldata/3306/data/db1/r.frm
    (system@127.0.0.1:3306) [db1]> flush table t for export
        -> ;
    Query OK, 0 rows affected (0.00 sec)
    
    (system@127.0.0.1:3306) [db1]> system ls -l /data/mysqldata/3306/data/db1/t.*
    -rw-r----- 1 mysql mysql    497 Mar 27 09:31 /data/mysqldata/3306/data/db1/t.cfg
    -rw-r----- 1 mysql mysql   8604 Mar 27 08:27 /data/mysqldata/3306/data/db1/t.frm
    -rw-r----- 1 mysql mysql 147456 Mar 27 08:27 /data/mysqldata/3306/data/db1/t.ibd
    (system@127.0.0.1:3306) [db1]> system cp /data/mysqldata/3306/data/db1/t.ibd /data/mysqldata/3306/data/db1/r.ibd
    (system@127.0.0.1:3306) [db1]> system cp /data/mysqldata/3306/data/db1/t.cfg /data/mysqldata/3306/data/db1/r.cfg
    (system@127.0.0.1:3306) [db1]> system ls -l /data/mysqldata/3306/data/db1/r.*
    -rw-r----- 1 mysql mysql 147456 Mar 27 09:34 /data/mysqldata/3306/data/db1/r.cfg
    -rw-r----- 1 mysql mysql   8604 Mar 27 09:30 /data/mysqldata/3306/data/db1/r.frm
    -rw-r----- 1 mysql mysql 147456 Mar 27 09:34 /data/mysqldata/3306/data/db1/r.ibd
    (system@127.0.0.1:3306) [db1]> unlock tables;
    Query OK, 0 rows affected (0.00 sec)
    (system@127.0.0.1:3306) [db1]> alter table r import tablespace;
    Query OK, 0 rows affected (0.02 sec)
    (system@127.0.0.1:3306) [db1]> select count(*) from r;
    +----------+
    | count(*) |
    +----------+
    |     1000 |
    +----------+
    1 row in set (0.00 sec)

    注意,如果出现

    (system@127.0.0.1:3306) [db1]> alter table r import tablespace;

    ERROR 1810 (HY000): IO Read error: (139863127226208, (null)) (null)

    要查看文件以及文件的权限是否都正确。

    流程的注意点

    --1 执行完flush table之后,db1.t整个表处于只读状态,直到执行unlock tables命令后才释放

    --2 在执行import tablespace的时候,为了让文件里的表空间id和数据字典一致,会修改r.ibd的表空间id,而这个表空间id存在于每个页中,

    因此,如果一个很大的文件,每个数据页都需要修改,可能会花很长时间,但是相比于mysqldump,还是比较快的。

     最后,可以使用pt的工具

    pt-archiver--将表数据归档到另一个表或文件中

    删除或归档一张大表,导出文件等,可以进行主从同步数据
    [mysql@mysqlt1 bin]$ ./pt-archiver --help
    Archive all rows from oltp_server to olap_server and to a file:
    pt-archiver --source h=oltp_server,D=test,t=tbl --dest h=olap_server 
      --file '/var/log/archive/%Y-%m-%d-%D.%t'                           
      --where "1=1" --limit 1000 --commit-each
    Purge (delete) orphan rows from child table:
    pt-archiver --source h=host,D=db,t=child --purge 
      --where 'NOT EXISTS(SELECT * FROM parent WHERE col=child.col)'
  • 相关阅读:
    Candy leetcode java
    Trapping Rain Water leetcode java
    Best Time to Buy and Sell Stock III leetcode java
    Best Time to Buy and Sell Stock II leetcode java
    Best Time to Buy and Sell Stock leetcode java
    Maximum Subarray leetcode java
    Word Break II leetcode java
    Word Break leetcode java
    Anagrams leetcode java
    Clone Graph leetcode java(DFS and BFS 基础)
  • 原文地址:https://www.cnblogs.com/yhq1314/p/10932163.html
Copyright © 2011-2022 走看看