MYSQL--索引学习(持续更新中……)


time 20210118

author Venki


  • IPC和MRR

  • 提高I/O效率:减少I/O的量和I/O的次数

  • 存储引擎是不同的数据文件在磁盘的组织形式,是一种实现数据索引结构的机制。

  • 为什么MySQL选择了B+树

    • hash函数设计不够好,导致hash表稀疏,否则导致哈希表利用率低,并且hash
  • MySQL的服务里面包含:连接器,解析器,优化器,执行器(不同的课程可能划分不一样)。

  • antlr和calcite用来作词法分析和语法分析。

  • RBO基于规则优化和CBO基于成本的优化。

  • 存储引擎:不同数据文件在磁盘的不同组织形式。

  • innodb和myisam的区别,MySQL5.5版本之后存储引擎默认myisam。

    • innodb支持事务,myisam不支持;
    • innodb支持外检,myisam不支持;
    • innodb支持行锁和表锁,myisam只支持表锁;
    • 索引存储的叶子节点的数据不同;
    • myisam count(*)比较快,不能带任何查询条件
  • MySQL8.0版本之后,MySQL服务的查询缓存取消,因为做更新操作,导致查询缓存命中率较低。

  • 存储引擎必须进行持久化落盘处理,memory存储引擎除外。

  • OLTP:联机事务处理-》关系型数据库-》时效性高和OLAP:联机分析处理-》数据仓库-》对历史数据分析,产生决策性影响。

  • myisam使用的数据结构是B+树,innodb默认使用B+树,同时也支持自适应hash数据结构。

  • 平衡二叉树(最短子树和最长子树高度差不能超过1),损失了一部分写入的性能,但是换来了查询的性能。

  • 红黑树要求最长子树深度和最短子树的高度差不能超过2倍,它是平衡树的一个折中,可以将查询和选择对半。缺点就是:数据加大,高度加深,导致I/O次数变多。

  • 局部性原理(空间和时间)数据程序聚集存放,刚刚查询过的数据有可能很快又被查询。

  • 磁盘预读

  • B树的每个结点都有数据,B+树只有叶子结点才存储数据。

  • B+树三层高度大约可以存储4096万条数据

  • B+树可以从根节点随机查找,也可以直接从页子节点直接查询。

  • innodb是通过B+Tree结构对主键创建索引,然后叶子节点中存储,如果没有主键,那么会选择唯一键,如果没有唯一键,那么会生成一个6字节的row_id来作为存储。

  • 如果创建索引的键是其他字段,那么在叶子节点中存储的是该记录的主键,然后通过主键索引找到记录,叫做回表。

  • 索引在一个索引文件中存储(分区表除外)。

  • 一个表的聚簇索引一定是主键索引吗?不一定,可以是唯一键。

  • 一个表的聚簇索引会有多个吗?只有一个。

  • 主键索引一定是聚簇索引吗(是)?假如说创建表的时候没有主键,没有唯一键,添加数据之后,设置了主键?

    • 会把row_id主键索引更改为刚刚设置的主键索引
    • 什么是聚簇索引(最简单的理解就是:数据和索引是否在一起存储)。

为什么innodb数据引擎,在当一个表设置主键索引后,会替换掉原来row_id?因为innodb数据引擎实现的数据结构中,数据是存储在最后的叶子节点上面的,试想如果这是不替换掉row_id,那么新设置的主键索引的叶子节点存储的就是row_id,那么在以where id=?查询中,要进行回表,也就是说,还要根据主键索引的叶子节点的row_id再次回表查询对应的数据,那么还不如直接替换掉row_id为主键索引,减少回表和I/O次数

  • innodb主键索引是聚簇索引,二级索引是非聚簇索引,myisam是非聚簇索引。

  • 唯一键为null值,可以走索引吗?null值不走索引的。

  • 一张表中理论上将可以包含N个索引(多少个列就多少个索引),但是并不是所有的列都适合简历索引。

  • 索引的分类:

    • 聚簇索引与非聚簇索引
    • 主键索引、唯一索引、普通索引+辅助索引+二级索引、全文索引、组合索引+联合索引
  • 一般情况下,SQL语句中尽可能多的带主键字段,方便进行查询,但是主键字段的条件一定会生效吗?答案:不一定。MySQL的优化器自己会选择最合适的优化。

  • 回表:二级索引需要再次依赖主键索引进行二次查询,该过程叫做回表。

SELECT * FROM t1 WHERE name = ? # 需要回表查询,因为是*

SELECT id,name FROM t1 WHERE name = ? # 不需要回表,通过name这棵树找到要查询的所有字段,可以直接返回,不需要从主键树中检索结果,此时叫索引覆盖。

执行计划中Extra:using index 就说明使用到了索引覆盖

  • innodb5.6之后支持全文索引
  • 最左匹配:是基于组合索引而言的
  • 索引下推:就可以用以下解释,只是查询条件的执行位置不同。
# 前提是zhangsan和age是一个组合索引。 

SELECT * FROM test WHERE name = zhangsan and age=18

# 在5.7版本之前是这样执行的:执行器从存储引擎中根据name的条件获取到所有的结果,然后将结果在执行器中按照age进行过滤。
# 在5.7版本后引入索引下推,根据name和age两个条件从存储引擎中做数据筛选,选出对应结果。

# 在执行计划,explain中的extra中出现using index condition就表示使用到了索引下推。
  • 组合索引:如果一个索引包含多个列,就称之为组合索引。

  • 有的时候组合索引跳过第一个字段,直接以第二个字段为查询条件也可以用到组合索引,原因是通过索引覆盖实现的。当所有表字段都建立索引,就要注意索引覆盖了。有的时候优化器会进行顺序优化。

  • 当一个表中的所有列都是索引时,它是不太符合最左匹配原则的。也就是说表中的字段不全都是索引时,才符合最左匹配原则。

  • 执行计划中有个索引长度key_len,举例:如果是5,可能组合就是4+1,因为整型占据4个字节,然后是否为空的判断占据1个字节(允许为空就需要+1个字节,不允许为空就不用加,varchar是一个可变字符,可变长度需要多申请2个字节,所以可能需要加2),总共就是5个字节,也就是索引长度就是5;查询条件中如果包含等号,是可以使用索引的,如果是包含大于小于的条件时会阻断后面索引。

  • 索引失效,查询条件用了表达式和函数。隐式转换也会导致索引失效。

  • or会不会使索引失效?要看具体情况而定,组合索引可能不会走索引,主键索引可能就会走。and会不会索引失效?多注意extra里面的提示:impossible where

  • B+树的叶子节点存储包含所有的数据。

  • innodb在插入的时候就会进行排序

  • 有的时候使用索引需要等价于扫描所有行,那么优化器就不会走索引。比如a字段建立了索引,但是查询a>1,相当于找所有的数据,这时候就走全表扫描,如果a>5,那么就会走索引了。

  • myisam的叶子节点存储的是文件所在磁盘的地址,innodb叶子节点存储的是数据记录。

  • 主键索引与唯一索引的区别:

    • 主键相当于一本书的页码,索引相当于书的目录。
    • 主键可以被其他表引用为外键,而唯一索引不能。
    • 唯一性索引列允许空值,而主键列不允许为空值。
  • 基于规则优化的RBO以及基于成本优化的CBO。

  • 8.0版本的缓存机制取消了,因为命中率太低了,因为数据表经常更新,导致缓存经常失效。

  • B+树和B树区别之一,就是B+树的叶子节点存储了数据,而非叶子节点没有存储记录数据,这样就可以存储更多的数据。

  • 索引设计的原则?

    • 适合索引的列是出现在where子句中的列,或者连接子句中指定的列;
    • 基数较小的类,索引效果较差,没有必要在此列建立索引;
    • 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间;
    • 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
  • 创建索引的原则(重中之重)索引虽好,但也不是无限制的使用,最好符合一下几个原则

    • 1) 最左前缀匹配原则,组合索引非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整;
    • 2)较频繁作为查询条件的字段才去创建索引;
    • 3)更新频繁字段不适合创建索引;
    • 4)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低);
    • 5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可;
    • 6)定义有外键的数据列一定要建立索引;
    • 7)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引;
    • 8)对于定义为text、image和bit的数据类型的列不要建立索引。


2020年4月13日

  • myisam存储引擎的数据表和innodb存储引擎的数据表,在插入记录时,myisam记录顺序就是插入时的顺序,而innodb记录顺序是按照主键排好序的顺序,但是需要注意的是,如果innodb存储引擎的表在创建时没有自定义主键索引(采用的是innodb自行维护的row_id为隐藏主键的索引),那么以innodb存储引擎为基础的表记录数据就是插入顺序(和myisam没有区别了)

  • 局部性原理与磁盘预读

    • 由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。程序运行期间所需要的数据通常比较集中。由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。
    • 预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页得大小通常为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。
  • 删除主键索引:alter table 表名 drop primary key(因为主键只有一个)。这里值得注意的是,如果主键自增长,那么不能直接执行此操作(自增长依赖于主键索引)alter table user_index -- 重新定义字段 MODIFY id int,drop PRIMARY KEY

  • 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

  • 前缀索引:我们可以利用select count(*)/count(distinct left(password,prefixLen));,通过从调整prefixLen的值(从1自增)查看不同前缀长度的一个平均匹配度,接近1时就可以了(表示一个密码的前prefixLen个字符几乎能确定唯一一条记录)。

  • B树与B+树的比较:

    • 在B树中,你可以将键和值存放在内部节点和叶子节点;但在B+树中,内部节点都是键,没有值,叶子节点同时存放键和值。
    • B+树的叶子节点有一条链相连,而B树的叶子节点各自独立。
    • B树可以在内部节点同时存储键和值,因此,把频繁访问的数据放在靠近根节点的地方将会大大提高热点数据的查询效率。这种特性使得B树在特定数据重复多次查询的场景中更加高效。由于B+树的内部节点只存放键,不存放值,因此,一次读取,可以在内存页中获取更多的键,有利于更快地缩小查找范围。 B+树的叶节点由一条链相连,因此,当需要进行一次全数据遍历的时候,B+树只需要使用O(logN)时间找到最小的一个节点,然后通过链进行O(N)的顺序遍历即可。而B树则需要对树的每一层进行遍历,这会需要更多的内存置换次数,因此也就需要花费更多的时间。
  • 为什么哈希结构的索引不支持范围查找:因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询。而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围。

  • 在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据,这就是聚簇索引和非聚簇索引。在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引。如果没有唯一键,则隐式的生成一个键来建立聚簇索引。

  • 聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据。

  • 非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因。

  • 澄清一个概念:innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值。

  • innodb索引在一个文件中存放,分区表除外。

  • 一个表的聚簇索引不一定是组件,也可能是唯一键,一个表的聚簇索引只有一个,聚簇索引一定是聚簇索引。

  • innodb主键索引是聚簇索引,myisam非聚簇索引。innodb的普通列索引是非聚簇索引。

  • null值是不走索引,索引尽量不要用null值作为列值。

  • 事务:事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。

  • 在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。

  • 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。

    • 特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 表级锁 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。

    • 特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
  • 页级锁 页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。

    • 特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
  • 共享锁: 又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。

  • 排他锁: 又叫做写锁。 当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。

用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的。一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以。
  • InnoDB存储引擎的锁的算法有三种:

    • Record lock:单个行记录上的锁;
    • Gap lock:间隙锁,锁定一个范围,不包括记录本身;
    • Next-key lock:record+gap 锁定一个范围,包含记录本身。
  • 死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

    • 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会;
    • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
    • 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率,如果业务处理不好可以用分布式事务锁或者使用乐观锁。
  • 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制。

  • 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。

  • 当一个表中全部列都建立索引时,是不太符合最左匹配原则的。

  • MySQL中InnoDB引擎的行锁是怎么实现的?

    • InnoDB是基于索引来完成行锁select * from tab_with_index where id = 1 for update;,for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起。
    • 只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
  • set autocommit=0指事务非自动提交,自此句执行以后,每个SQL语句或者语句块所在的事务都需要显示"commit"才能提交事务。

    • 不管autocommit 是1还是0 ,START TRANSACTION 后,只有当commit数据才会生效,ROLLBACK后就会回滚。
    • 当autocommit 为 0 时,不管有没有START TRANSACTION。
    • 如果autocommit 为1 ,并且没有START TRANSACTION 。调用ROLLBACK是没有用的。即便设置了SAVEPOINT。只有当commit数据才会生效,ROLLBACK后就会回滚。
  • for update 仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效。

  • 当对存在的行进行锁的时候(主键),mysql就只有行锁。

  • 当对未存在的行进行锁的时候(即使条件为主键),mysql是会锁住一段范围(有gap锁)

自己理解脏读、不可重复读、幻读。脏读:多个事务之间,均为提交,但是其中一个事务查询多此查询同一结果不一样(比如库存第一次查询是1,第二次查询是2);不可重复读:单个事务内,多次读取同一结果不一样,是另一个已提交事务在此中间更新了数据(例如A事务一次查询库存时为1,此时B事务为更新库存操作+1而且B事务已完成提交动作,A事务二次查询时,发现库存变成2,);幻读:多个事务之间,一个事务多次查询记录数不一样,是因为在此期间其他已完成的事务新插入记录(A事务查询库存大于1的商品有20个,此时其他事务有新增商品操作,新增2类库存为2的商品,导致A事务二次查询时,商品变为22个)。

  • 组合索引才可能发生索引下推(查询条件如果是常量就没必要索引下推)。
  • 索引长度,varchar如果是utf8字符集一个字符占据3个字节。可变长度需要多申请2个字节(为了标注当前实际长度)。
  • 索引失效,查询条件使用函数id+1=4
  • 隐私转换可能导致索引失效查询条件 phone=15011111111索引失效,phone='15011111111'使用索引
  • or的时候可能导致索引失效,and会导致索引失效,此时要注意extra可能查询条件本身就不存在。
  • 索引覆盖的时候,第一棵索引树中如果包含了要查询的字段那么就可以走索引覆盖,否则还是继续回表,所以可以通过建立组合索引提高覆盖索引。
  • binlog:归属于mysql的server层的;redolog以及undolog:归属于innodb的存储引擎。


2020年4月14日

  • 慢日志查询记录:

    • 配置项:slow_query_log,可以使用show variables like ‘slov_query_log’查看是否开启,如果状态值为OFF,可以使用set GLOBAL slow_query_log = on来开启,它会在datadir下产生一个xxx-slow.log的文件。
    • 设置临界时间,配置项:long_query_time,查看:show VARIABLES like ‘long_query_time’,单位秒,设置:set long_query_time=0.5。
    • 实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉,查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log中。
  • 慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

    • 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
    • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
    • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。
  • 一定要注意int和char的区别,int(10),10表示可以存储的长度并不是大小,char(10)表示存储的大小,即最多存储10个字符,并且int(10)占据4个字节,并不是104字节,char(10)占据3个字节并不是203个字节。

  • mysql优化思路:

    • 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。
    • 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
    • 应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
    • 应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。(因为mysql是基于成本优化的,所以优化器可能会根据这一原则选择是否使用索引)
    • in 和 not in 也要慎用,否则会导致全表扫描。
    • 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。
    • 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
    • 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。
    • 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。


2020年4月15日

  • 服务器CPU飙升到50%以上,如何排查

    • 当 cpu 飙升到 500%时,先用操作系统命令 top 命令观察是不是 mysqld 占用导致的,如果不是,找出占用高的进程,并进行相关处理。
    • 如果是 mysqld 造成的, show processlist,看看里面跑的 session 情况,是不是有消耗资源的 sql 在运行。找出消耗高的 sql,看看执行计划是否准确, index 是否缺失,或者实在是数据量太大造成。
    • 一般来说,肯定要 kill 掉这些线程(同时观察 cpu 使用率是否下降),等进行相应的调整(比如说加索引、改 sql、改内存参数)之后,再重新跑这些 SQL。
    • 也有可能是每个 sql 消耗资源并不多,但是突然之间,有大量的 session 连进来导致 cpu 飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等。
  • 垂直分表

    • 垂直拆分的优点:

      • 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。
      • 垂直分区可以简化表的结构,易于维护。
    • 垂直分表的缺点:

      • 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。
      • 垂直分区会让事务变得更加复杂。
      • 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表逻辑都会改变,扩展性较差。
      • 对于应用层来说,逻辑算法增加开发成本。
  • 水平分表

    • 水平分区的缺点:

      • 给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需UNION操作。
      • 在许多数据库应用中,这种复杂度会超过它带来的优点,查询时会增加读一个索引层的磁盘次数。
  • 分表之后,带来的问题?

    • 事务支持,分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
    • 跨库join,只要是进行切分,跨节点Join的问题是不可避免的。但是良好的设计和切分却可以减少此类情况的发生。解决这一问题的普遍做法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。分库分表方案产品。
    • 跨节点的count,order by,group by以及聚合函数问题 这些是一类问题,因为它们都需要基于全部数据集合进行计算。多数的代理都不会自动处理合并工作。解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题。
    • 数据迁移,容量规划,扩容等问题 来自淘宝综合业务平台团队,它利用对2的倍数取余具有向前兼容的特性(如对4取余得1的数对2取余也是1)来分配数据,避免了行级别的数据迁移,但是依然需要进行表级别的迁移,同时对扩容规模和分表数量都有限制。总得来说,这些方案都不是十分的理想,多多少少都存在一些缺点,这也从一个侧面反映出了Sharding扩容的难度。
    • ID问题,一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由.一些常见的主键生成策略。
  • 分区分表后,索引怎么处理?

  • 主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致。

    • 主数据库出现问题,可以切换到从数据库。
    • 可以进行数据库层面的读写分离。
    • 可以在从数据库上进行日常备份。
  • MySQL主从复制工作原理:

    • 在主库上把数据更高记录到二进制日志;
    • 从库将主库的日志复制到自己的中继日志;
    • 从库读取中继日志的事件,将其重放到从库数据中。
  • 数据库备份

    • 逻辑备份

      • mysqldump 属于逻辑备份。加入–single-transaction 选项可以进行一致性备份。后台进程会先设置 session 的事务隔离级别为 RR(SET SESSION TRANSACTION ISOLATION LEVELREPEATABLE READ),之后显式开启一个事务(START TRANSACTION /*!40100 WITH CONSISTENTSNAPSHOT */),这样就保证了该事务里读到的数据都是事务事务时候的快照。之后再把表的数据读取出来。如果加上–master-data=1 的话,在刚开始的时候还会加一个数据库的读锁(FLUSH TABLES WITH READ LOCK),等开启事务后,再记录下数据库此时 binlog 的位置(showmaster status),马上解锁,再读取表的数据。等所有的数据都已经导完,就可以结束事务。
    • 物理备份

      • xtrabackup 属于物理备份,直接拷贝表空间文件,同时不断扫描产生的 redo 日志并保存下来。最后完成 innodb 的备份后,会做一个flushenginelogs的操作(老版本在有bug,在5.6上不做此操作会丢数据),确保所有的redo log 都已经落盘(涉及到事务的两阶段提交概念,因为 xtrabackup并不拷贝binlog,所以必须保证所有的redolog都落盘,否则可能会丢最后一组提交事务的数据)。这个时间点就是innodb完成备份的时间点,数据文件虽然不是一致性的,但是有这段时间的 redo 就可以让数据文件达到一致性(恢复的时候做的事情)。然后还需要 flush tables with read lock,把 myisam 等其他引擎的表给备份出来,备份完后解锁。这样就做到了完美的热备。
  • 逻辑备份时间是物理备份时间的5倍左右。

  • 数据表损坏如何修复

    • 1)修复前将mysql服务停止。
    • 2)打开命令行方式,然后进入到mysql的/bin目录。
    • 3)执行myisamchk –recover 数据库所在路径/*.MYI
  • OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了OPTIMIZE TABLE命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库)。

陌生词语

  1. 2PC(二阶段提交协议)

事务协调者先向事务参与者发出准备阶段的操作(你们开始各自执行自己的事务,但是不要提交和回滚,执行完后告诉我一声),两个参与者只是完成了该完成的SQL,但是还没有执行commit或者rollback操作,他们需要向事务的协调者返回一个状态,事务协调者接收到状态,经过经过判断,再次向事务参与者发出指令,提交或者回滚的命令。

  1. 3PC(三阶段提交协议)

3PC最关键要解决的就是协调者和参与者同时挂掉的问题,所以3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。在第一阶段,只是询问所有参与者是否可可以执行事务操作,并不在本阶段执行事务操作。当协调者收到所有的参与者都返回YES时,在第二阶段才执行事务操作,然后在第三阶段在执行commit或者rollback。

猜你喜欢

转载自blog.csdn.net/qq_38721452/article/details/115556208