• MySQL权限控制、分区表、快速复制表


    1. 主键id出现自增id不连续的原因

    MySQL只保证了自增id是递增的,但不保证是连续的。

    唯一键冲突:插入的时候先将自增值自增,然后插入,如果唯一键冲突插入失败,自增值不会回滚。
    事务回滚:事务执行失败,自增值也不会回滚。
    批量插入数据:批量申请自增id的策略会造成id浪费。同一个语句去申请自增id,每次申请到的自增id个数都是上一次的两倍。

    2. insert … select

    insert … select 是很常见的在两个表之间拷贝数据的方法。你需要注意,在可重复读隔离级别下,这个语句会给select的表里扫描到的记录和间隙加读锁。

    而如果insert和select的对象是同一个表,则有可能会造成循环写入。这种情况下,我们需要引入用户临时表来做优化。

    insert 语句如果出现唯一键冲突,会在冲突的唯一值上加共享的next-key lock(S锁)。因此,碰到由于唯一键约束导致报错后,要尽快提交或回滚事务,避免加锁时间过长。

    3.最快地复制一张表

    我们来对比一下这三种方法的优缺点:

    物理拷贝的方式速度最快,尤其对于大表拷贝来说是最快的方法。如果出现误删表的情况,用备份恢复出误删之前的临时库,然后再把临时库中的表拷贝到生产库上,是恢复数据最快的方法。但是,这种方法的使用也有一定的局限性:
    必须是全表拷贝,不能只拷贝部分数据;
    需要到服务器上拷贝数据,在用户无法登录数据库主机的场景下无法使用;
    由于是通过拷贝物理文件实现的,源表和目标表都是使用InnoDB引擎时才能使用。

    用mysqldump生成包含INSERT语句文件的方法,可以在where参数增加过滤条件,来实现只导出部分数据。这个方式的不足之一是,不能使用join这种比较复杂的where条件写法。

    用select … into outfile的方法是最灵活的,支持所有的SQL写法。但,这个方法的缺点之一就是,每次只能导出一张表的数据,而且表结构也需要另外的语句单独备份。

    后两种方式都是逻辑备份方式,是可以跨引擎使用的。

    4. 权限控制

    4.1 创建用户:

    create user ‘ua’@‘%’ identified by ‘pa’;

    这条语句的逻辑是创建一个用户’ua’@’%’,密码是pa。注意,在MySQL里面,用户名(user)+地址(host)才表示一个用户,因此 ua@ip1 和 ua@ip2代表的是两个不同的用户。

    这条命令做了两个动作:

    磁盘上,往mysql.user表里插入一行,由于没有指定权限,所以这行数据上所有表示权限的字段的值都是N;
    内存里,往数组acl_users里插入一个acl_user对象,这个对象的access字段值为0。

    4.2 全局权限

    全局权限,作用于整个MySQL实例,这些权限信息保存在mysql库的user表里。如果我要给用户ua赋一个最高权限的话,语句是这么写的:

    grant all privileges on . to ‘ua’@‘%’ with grant option;

    这个grant命令做了两个动作:

    磁盘上,将mysql.user表里,用户’ua’@’%'这一行的所有表示权限的字段的值都修改为‘Y’;
    内存里,从数组acl_users中找到这个用户对应的对象,将access值(权限位)修改为二进制的“全1”。

    在这个grant命令执行完成后,如果有新的客户端使用用户名ua登录成功,MySQL会为新连接维护一个线程对象,然后从acl_users数组里查到这个用户的权限,并将权限值拷贝到这个线程对象中。之后在这个连接中执行的语句,所有关于全局权限的判断,都直接使用线程对象内部保存的权限位。

    基于上面的分析我们可以知道:

    grant 命令对于全局权限,同时更新了磁盘和内存。命令完成后即时生效,接下来新创建的连接会使用新的权限。
    对于一个已经存在的连接,它的全局权限不受grant命令的影响。

    需要说明的是,一般在生产环境上要合理控制用户权限的范围。我们上面用到的这个grant语句就是一个典型的错误示范。如果一个用户有所有权限,一般就不应该设置为所有IP地址都可以访问。

    如果要回收上面的grant语句赋予的权限,你可以使用下面这条命令:

    revoke all privileges on . from ‘ua’@‘%’;

    这条revoke命令的用法与grant类似,做了如下两个动作:

    磁盘上,将mysql.user表里,用户’ua’@’%'这一行的所有表示权限的字段的值都修改为“N”;
    内存里,从数组acl_users中找到这个用户对应的对象,将access的值修改为0。

    4.3 db权限

    除了全局权限,MySQL也支持库级别的权限定义。如果要让用户ua拥有库db1的所有权限,可以执行下面这条命令:

    grant all privileges on db1.* to ‘ua’@‘%’ with grant option;

    基于库的权限记录保存在mysql.db表中,在内存里则保存在数组acl_dbs中。这条grant命令做了如下两个动作:

    磁盘上,往mysql.db表中插入了一行记录,所有权限位字段设置为“Y”;
    内存里,增加一个对象到数组acl_dbs中,这个对象的权限位为“全1”。

    4.4 表权限和列权限

    除了db级别的权限外,MySQL支持更细粒度的表权限和列权限。其中,表权限定义存放在表mysql.tables_priv中,列权限定义存放在表mysql.columns_priv中。这两类权限,组合起来存放在内存的hash结构column_priv_hash中。

    这两类权限的赋权命令如下:

    create table db1.t1(id int, a int);

    grant all privileges on db1.t1 to ‘ua’@‘%’ with grant option;
    GRANT SELECT(id), INSERT (id,a) ON mydb.mytbl TO ‘ua’@‘%’ with grant option;

    跟db权限类似,这两个权限每次grant的时候都会修改数据表,也会同步修改内存中的hash结构。因此,对这两类权限的操作,也会马上影响到已经存在的连接。

    正常情况下,grant命令之后,没有必要跟着执行flush privileges命令。

    grant语句会同时修改数据表和内存,判断权限的时候使用的是内存数据。因此,规范地使用grant和revoke语句,是不需要随后加上flush privileges语句的。

    flush privileges语句本身会用数据表的数据重建一份内存权限数据,所以在权限数据可能存在不一致的情况下再使用。而这种不一致往往是由于直接用DML语句操作系统权限表导致的,所以我们尽量不要使用这类语句。

    5. 分区表

    分区表:
    MySQL在第一次打开分区表的时候,需要访问所有的分区;
    在server层,认为这是同一张表,因此所有分区共用同一个MDL锁;
    在引擎层,认为这是不同的表,因此MDL锁之后的执行过程,会根据分区表规则,只访问必要的分区。

    实际使用时,分区表跟用户分表比起来,有两个绕不开的问题:一个是第一次访问的时候需要访问所有分区,另一个是共用MDL锁。

    因此,如果要使用分区表,就不要创建太多的分区。这里有两个问题需要注意:

    分区并不是越细越好。实际上,单表或者单分区的数据一千万行,只要没有特别大的索引,对于现在的硬件能力来说都已经是小表了。

    分区也不要提前预留太多,在使用之前预先创建即可。比如,如果是按月分区,每年年底时再把下一年度的12个新分区创建上即可。对于没有数据的历史分区,要及时的drop掉。

    至于分区表的其他问题,比如查询需要跨多个分区取数据,查询性能就会比较慢,基本上就不是分区表本身的问题,而是数据量的问题或者说是使用方式的问题了。

    分区表和手工分表,一个是由server层来决定使用哪个分区,一个是由应用层代码来决定使用哪个分表。因此,从引擎层看,这两种方式也是没有差别的。

    其实这两个方案的区别,主要是在server层上。从server层看,我们就不得不提到分区表一个被广为诟病的问题:打开表的行为。

    当然,如果你的团队已经维护了成熟的分库分表中间件,用业务分表,对业务开发同学没有额外的复杂性,对DBA也更直观,自然是更好的。

  • 相关阅读:
    如何做顶级“新生代农民工”?这几本书为你打开大门
    某大厂高级测试岗位面试题...
    门控循环单元(GRU)【动手学深度学习v2】
    [附源码]计算机毕业设计JAVA鑫地酒店酒水库存管理系统论文
    String, Int 和 Byte数组
    Spark基础:Kafka分布式消息系统
    uniapp+vue3+ts+uview-plus搭建项目步骤
    【rar密码】WinRAR整理密码,如何使用?
    nodejs事件循环
    MindSpore报错显示parameter没有zero属性
  • 原文地址:https://blog.csdn.net/qq_44300280/article/details/126268826