• 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)'
  • 相关阅读:
    Linux 下的dd命令使用详解
    理解Linux的inode
    2021.11.11
    转一篇DLL逆向的文章,适用于一般的dll逆向
    关于Exchange DSAccess组件目录检测机制
    一些KB
    Inside of my heart
    C/C++是程序员必须掌握的语言吗?
    一个自动检测并安装hotfix的脚本
    VC++中DLL的创建和使用
  • 原文地址:https://www.cnblogs.com/yhq1314/p/10932163.html
Copyright © 2020-2023  润新知