CREATE TABLE 表名 AS SELECT 语句 快速复制表但是锁表

2021-01-13 17:23:21

create table as select  能快速复制表,但是又个确定,它会锁表。哎

根据情况使用吧,小一点的表还是可以的

解决方案,只能类似这样 

create table new_table as select ... join ... group by ... limit 0;

insert into new_table as select ... join ... group by ...

参考地址 create table as select性能测试


MySQL的insert into select 引发锁表


Create table as select性能简介:


又是被大佬嫌弃的一天,为了不卷铺盖走人,我决定去学习一下表备份的常见方法。

MySQL一般我们在生产上备份数据通常会用到 这两种方法:

  1. INSERT INTO SELECT

  2. CREATE TABLE AS SELECT

注:本文仅针对MySQL innodb引擎,事务是可重复读RR,数据库版本为5.5

1.INSERT INTO SELECT

insert into Table2(field1,field2,...) select value1,value2,... from Table1

注意

(1)要求目标表Table2必须存在,并且字段field,field2…也必须存在

(2)注意Table2的主键约束,如果Table2有主键而且不为空,则 field1, field2…中必须包括主键

在执行语句的时候,MySQL是逐行加锁的(扫描一个锁一个),直至锁住所有符合条件的数据,执行完毕才释放锁。所以当业务在进行的时候,切忌使用这种方法。

在RR隔离级别下,还会加行锁和间隙锁

举个栗子吧:

CREATE TABLE `t` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `c` (`c`)
) ENGINE=InnoDB;

insert into t values(null, 1,1);
insert into t values(null, 2,2);
insert into t values(null, 3,3);
insert into t values(null, 4,4);

create table t2 like t;

执行

begin;
insert into t2(c,d) select c,d from t;

先不commit;这个语句对表 t 主键索引加了 (-∞,1] 这个 next-key lock

新开一个Navicat窗口,模拟新事务进入,此时执行下面这句sql就需要等待

insert into t values(-1,-1,-1);

锁住了

真就锁表了~无法写进去了,我终于知道为什么订单超时了。

背锅背锅。

如果实在要使用 INSERT INTO SELECT 这种方法,可以使用下面的方法进行优化:

  1. 加条件,强制走索引,不要全表扫描,例如

INSERT INTO Table2 SELECT
    * 
FROM
    Table1 FORCE INDEX (create_time)
WHERE
    update_time <= '2020-03-08 00:00:00';
  1. 加上limit 100,100 这种,限制数量

2. CREATE TABLE AS SELECT

create table as select 会创建一个不存在的表,也可以用来复制一个表。

1. create table t3 as select * from t where 1=2;
-- 创建一个表结构与t一模一样的表,只复制结构不复制数据;

2.create table t3 as select * from t ;
-- 创建一个表结构与t一模一样的表,复制结构同时也复制数据;(索引不会创建)

3.create table t3(`id`,`a`)  as select `id`,`c` from t;
-- 创建一个表结构与t一模一样的表,复制结构同时也复制数据,但是指定新表的列名;

后面两种格式,如果后面跟上合适的查询条件,可以只复制符合条件的数据到新的表中。比如:

create  table table1  as  select * from table2  where columns1>=1;

针对大表多字段的表复制,考虑是否每一个字段都是必需的,如果不是必需的,可以自定义选择字段吗,这样复制的时间会大大提升。

CREATE table table1 as SELECT id FROM table2; -- 只复制id这一列

注意此建表过程全程锁表。语句执行完毕,才释放元数据锁

MDL全称为metadata lock,即元数据锁。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务(显式或隐式)的时候,不可以对元数据进行写入操作。因此从MySQL5.5版本开始引入了MDL锁,来保护表的元数据信息,用于解决或者保证DDL操作与DML操作之间的一致性。

注意:

  1. 新表不会自动创建创建和原表相同的索引。(即复制表的索引会消失)

3 .区别

  • 首先,最大的区别是二者属于不同类型的语句,INSERT INTO SELECT 是DML语句(数据操作语言,SQL中处理数据等操作统称为数据操纵语言),完成后需要提交才能生效,CREATE TABLE AS SELECT 是DDL语句(数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言 ),执行完直接生效,不提供回滚,效率比较高。

  • 其次,功能不同,INSERT INTO SELECT只是插入数据,必须先建表;CREATE TABLE AS SELECT 则建表和插入数据一块完成。

  • 当有大量数据的时候不推荐使用Insert into as,因为该语句的插入的效率很慢。

4.总结

以上对复制表来说,都不是很好的选择,分享几种平时常用的方法:

导出成excel,然后拼sql 成 insert into values(),(),()的形式。

定时任务,任务的逻辑是查询100条记录,然后多个线程分到几个任务执行,比如是个线程,每个线程10条记录,插入后,在查询新的100条记录处理。

mysqldumb方法,例如

导出 CSV 文件

select * from db1.t where a>900 into outfile '/server_tmp/t.csv';

第3、4两种方法适合整个表导出。

5. 业务少的情况(深夜什么的)下,可以使用 create table as select 。

知识又增加了。



  • 2017-09-05 11:48:16

    Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)

    容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描述(类、接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” 、“依赖注入(DI)”。本文就从这里开始。

  • 2017-09-11 09:22:09

    nginx配置返回文本或json

     有些时候请求某些接口的时候需要返回指定的文本字符串或者json字符串,如果逻辑非常简单或者干脆是固定的字符串,那么可以使用nginx快速实现,这样就不用编写程序响应请求了,可以减少服务器资源占用并且响应性能非常快

  • 2017-09-11 11:30:09

    linux 获取经过N层Nginx转发的访问来源真实IP

    通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址。如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:

  • 2017-09-11 16:15:11

    Nginx日志管理

    通过访问日志,你可以得到用户地域来源、跳转来源、使用终端、某个URL访问量等相关信息;通过错误日志,你可以得到系统某个服务或server的性能瓶颈等。因此,将日志好好利用,你可以得到很多有价值的信息。

  • 2017-09-11 16:34:14

    Nginx如何保留真实IP和获取前端IP

    squid,varnish以及nginx等,在做反向代理的时候,因为要代替客户端去访问服务器,所以,当请求包经过反向代理后,在代理服务器这里这个IP数据包的IP包头做了修改,最终后端web服务器得到的数据包的头部的源IP地址是代理服务器的IP地址,这样一来,后端服务器的程序给予IP的统计功能就没有任何意义,所以在做代理或集群的时候必须解决这个问题,这里,我以nginx做集群或代理的时候如何给后端web服务器保留(确切的说是传递)客户端的真实IP地址。