关于mysql:最新最全的-MySQL-面试题整理吊打面试官完全没问题了建议收藏

61次阅读

共计 34417 个字符,预计需要花费 87 分钟才能阅读完成。

数据库基础知识

为什么要应用数据库
  • 数据保留在内存

    • 长处:存取速度快
    • 毛病:数据不能永恒保留
  • 数据保留在文件

    • 长处:数据永恒保留
    • 毛病:1)速度比内存操作慢,频繁的 IO 操作。2)查问数据不不便
  • 数据保留在数据库

    • 数据永恒保留
    • 应用 SQL 语句,查问不便效率高。
    • 治理数据不便
什么是 SQL?

结构化查询语言 (Structured Query Language) 简称 SQL,是一种数据库查询语言(12800 字!SQL 语法速成手册)。

作用:用于存取数据、查问、更新和治理关系数据库系统。

什么是 MySQL?

MySQL 是一个关系型数据库管理系统,由瑞典 MySQL) AB 公司开发,属于 Oracle 旗下产品。MySQL 是最风行的关系型数据库管理系统之一,在 WEB 利用方面,MySQL 是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。在 Java 企业级开发中十分罕用,因为 MySQL 是开源收费的,并且不便扩大。

数据库三大范式是什么
  • 第一范式:每个列都不能够再拆分。
  • 第二范式:在第一范式的根底上,非主键列齐全依赖于主键,而不能是依赖于主键的一部分。
  • 第三范式:在第二范式的根底上,非主键列只依赖于主键,不依赖于其余非主键。

在设计数据库构造的时候,要尽量恪守三范式,如果不恪守,必须有足够的理由。比方性能。事实上咱们常常会为了性能而斗争数据库的设计。

mysql 无关权限的表都有哪几个

MySQL 服务器通过权限表来管制用户对数据库的拜访,权限表寄存在 mysql 数据库里,由 mysql_install_db 脚本初始化。这些权限表别离user,db,table_priv,columns_priv 和 host。上面别离介绍一下这些表的构造和内容:

user 权限表:记录容许连贯到服务器的用户帐号信息,外面的权限是全局级的。
db 权限表:记录各个帐号在各个数据库上的操作权限。
table_priv 权限表:记录数据表级的操作权限。
columns_priv 权限表:记录数据列级的操作权限。
host 权限表:配合 db 权限表对给定主机上数据库级操作权限作更粗疏的管制。这个权限表不受 GRANT 和 REVOKE 语句的影响。

MySQL 的 binlog 有有几种录入格局?别离有什么区别?

有三种格局,statement,row 和 mixed。ROW 还是 STATEMENT?线上 MySQL Binlog 怎么选?

  • statement 模式下,每一条会批改数据的 sql 都会记录在 binlog 中。不须要记录每一行的变动,缩小了 binlog 日志量,节约了 IO,进步性能。因为 sql 的执行是有上下文的,因而在保留的时候须要保留相干的信息,同时还有一些应用了函数之类的语句无奈被记录复制。
  • row 级别下,不记录 sql 语句上下文相干信息,仅保留哪条记录被批改。记录单元为每一行的改变,根本是能够全部记下来然而因为很多操作,会导致大量行的改变(比方 alter table),因而这种模式的文件保留的信息太多,日志量太大。
  • mixed,一种折中的计划,一般操作应用 statement 记录,当无奈应用 statement 的时候应用 row。

此外,新版的 MySQL 中对 row 级别也做了一些优化,当表构造发生变化的时候,会记录语句而不是逐行记录。赞!7000 字学习笔记,MySQL 从入门到放弃

数据类型

mysql 有哪些数据类型


  • 整数类型

    • 包含 TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,别离示意 1 字节、2 字节、3 字节、4 字节、8 字节整数。任何整数类型都能够加上 UNSIGNED 属性,示意数据是无符号的,即非负整数。
    • 长度:整数类型能够被指定长度,例如:INT(11)示意长度为 11 的 INT 类型。长度在大多数场景是没有意义的,它不会限度值的非法范畴,只会影响显示字符的个数,而且须要和 UNSIGNED ZEROFILL 属性配合应用才有意义。
    • 例子,假设类型设定为 INT(5),属性为 UNSIGNED ZEROFILL,如果用户插入的数据为 12 的话,那么数据库理论存储数据为 00012。
  • 实数类型

    • 包含 FLOAT、DOUBLE、DECIMAL。
    • DECIMAL 能够用于存储比 BIGINT 还大的整型,能存储准确的小数。
    • 而 FLOAT 和 DOUBLE 是有取值范畴的,并反对应用规范的浮点进行近似计算。
    • 计算时 FLOAT 和 DOUBLE 相比 DECIMAL 效率更高一些,DECIMAL 你能够了解成是用字符串进行解决。
  • 字符串类型

    • 包含 VARCHAR、CHAR、TEXT、BLOB
    • VARCHAR 用于存储可变长字符串,它比定长类型更节俭空间。
    • VARCHAR 应用额定 1 或 2 个字节存储字符串长度。列长度小于 255 字节时,应用 1 字节示意,否则应用 2 字节示意。
    • VARCHAR 存储的内容超出设置的长度时,内容会被截断。
    • CHAR 是定长的,依据定义的字符串长度调配足够的空间。
    • CHAR 会依据须要应用空格进行填充不便比拟。
    • CHAR 适宜存储很短的字符串,或者所有值都靠近同一个长度。
    • CHAR 存储的内容超出设置的长度时,内容同样会被截断。
应用策略:
  • 对于常常变更的数据来说,CHAR 比 VARCHAR 更好,因为 CHAR 不容易产生碎片。
  • 对于十分短的列,CHAR 比 VARCHAR 在存储空间上更有效率。
  • 应用时要留神只调配须要的空间,更长的列排序时会耗费更多内存。
  • 尽量避免应用 TEXT/BLOB 类型,查问时会应用长期表,导致重大的性能开销。
  • 枚举类型(ENUM),把不反复的数据存储为一个预约义的汇合。

    • 有时能够应用 ENUM 代替罕用的字符串类型。
    • ENUM 存储十分紧凑,会把列表值压缩到一个或两个字节。
    • ENUM 在外部存储时,其实存的是整数。
    • 尽量避免应用数字作为 ENUM 枚举的常量,因为容易凌乱。
    • 排序是依照外部存储的整数
  • 日期和工夫类型,尽量应用 timestamp,空间效率高于 datetime,

    • 用整数保留工夫戳通常不不便解决。
    • 如果须要存储奥妙,能够应用 bigint 存储。

引擎

MySQL 存储引擎 MyISAM 与 InnoDB 区别

存储引擎 Storage engine:MySQL 中的数据、索引以及其余对象是如何存储的,是一套文件系统的实现。

罕用的存储引擎有以下:
  • Innodb 引擎:Innodb 引擎提供了对数据库 ACID 事务的反对。并且还提供了行级锁和外键的束缚。它的设计的指标就是解决大数据容量的数据库系统。
  • MyIASM 引擎(本来 Mysql 的默认引擎):不提供事务的反对,也不反对行级锁和外键。
  • MEMORY 引擎:所有的数据都在内存中,数据的处理速度快,然而安全性不高。
MyISAM 与 InnoDB 区别


MyISAM 索引与 InnoDB 索引的区别?
  • InnoDB 索引是聚簇索引,MyISAM 索引是非聚簇索引。
  • InnoDB 的主键索引的叶子节点存储着行数据,因而主键索引十分高效。
  • MyISAM 索引的叶子节点存储的是行数据地址,须要再寻址一次能力失去数据。
  • InnoDB 非主键索引的叶子节点存储的是主键和其余带索引的列数据,因而查问时做到笼罩索引会十分高效。
InnoDB 引擎的 4 大个性
  • 插入缓冲(insert buffer)
  • 二次写(double write)
  • 自适应哈希索引(ahi)
  • 预读(read ahead)
存储引擎抉择

如果没有特地的需要,应用默认的 Innodb 即可。

MyISAM:以读写插入为主的应用程序,比方博客零碎、新闻门户网站。

Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,反对事务和外键。比方 OA 自动化办公零碎。

索引

什么是索引?

索引是一种非凡的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们蕴含着对数据表里所有记录的援用指针。

索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以帮助疾速查问、更新数据库表中数据。索引的实现通常应用 B 树及其变种 B + 树。

更艰深的说,索引就相当于目录。为了不便查找书中的内容,通过对内容建设索引造成目录。索引是一个文件,它是要占据物理空间的。

索引有哪些优缺点?
  • 索引的长处

    • 能够大大放慢数据的检索速度,这也是创立索引的最次要的起因。
    • 通过应用索引,能够在查问的过程中,应用优化暗藏器,进步零碎的性能。
  • 索引的毛病

    • 工夫方面:创立索引和保护索引要消耗工夫,具体地,当对表中的数据进行减少、删除和批改的时候,索引也要动静的保护,会升高增 / 改 / 删的执行效率;
    • 空间方面:索引须要占物理空间。
索引应用场景(重点)
  • where

上图中,依据 id 查问记录,因为 id 字段仅建设了主键索引,因而此 SQL 执行可选的索引只有主键索引,如果有多个,最终会选一个较优的作为检索的根据。

-- 减少一个没有建设索引的字段
alter table innodb1 add sex char(1);
-- 按 sex 检索时可选的索引为 null
EXPLAIN SELECT * from innodb1 where sex='男';

能够尝试在一个字段未建设索引时,依据该字段查问的效率,而后对该字段建设索引(alter table 表名 add index(字段名)),同样的 SQL 执行的效率,你会发现查问效率会有显著的晋升(数据量越大越显著)。

  • order by

当咱们应用 order by 将查问后果依照某个字段排序时,如果该字段没有建设索引,那么执行打算会将查问出的所有数据应用内部排序(将数据从硬盘分批读取到内存应用外部排序,最初合并排序后果),这个操作是很影响性能的,因为须要将查问波及到的所有数据从磁盘中读到内存(如果单条数据过大或者数据量过多都会升高效率),更无论读到内存之后的排序了。

然而如果咱们对该字段建设索引 alter table 表名 add index(字段名),那么因为索引自身是有序的,因而间接依照索引的程序和映射关系逐条取出数据即可。而且如果分页的,那么只用取出索引表某个范畴内的索引对应的数据,而不必像上述那取出所有数据进行排序再返回某个范畴内的数据。(从磁盘取数据是最影响性能的)

  • join

对 join 语句匹配关系(on)波及的字段建设索引可能提高效率

  • 索引笼罩

如果要查问的字段都建设过索引,那么引擎会间接在索引表中查问而不会拜访原始数据(否则只有有一个字段没有建设索引就会做全表扫描),这叫索引笼罩。因而咱们须要尽可能的在 select 后只写必要的查问字段,以减少索引笼罩的几率。

这里值得注意的是不要想着为每个字段建设索引,因为优先应用索引的劣势就在于其体积小。

索引有哪几种类型?
  • 主键索引: 数据列不容许反复,不容许为 NULL,一个表只能有一个主键。
  • 惟一索引: 数据列不容许反复,容许为 NULL 值,一个表容许多个列创立惟一索引。

    能够通过 ALTER TABLE table_name ADD UNIQUE (column); 创立惟一索引
    
    能够通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创立惟一组合索引
  • 一般索引: 根本的索引类型,没有唯一性的限度,容许为 NULL 值。

    能够通过 ALTER TABLE table_name ADD INDEX index_name (column); 创立一般索引
    
    能够通过 ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3); 创立组合索引
  • 全文索引:是目前搜索引擎应用的一种关键技术。

    能够通过 ALTER TABLE table_name ADD FULLTEXT (column); 创立全文索引
    索引的数据结构(b 树,hash)

    索引的数据结构和具体存储引擎的实现无关,在 MySQL 中应用较多的索引有 Hash 索引,B+ 树索引等,而咱们常常应用的 InnoDB 存储引擎的默认索引实现为:B+ 树索引。对于哈希索引来说,底层的数据结构就是哈希表,因而在绝大多数需要为单条记录查问的时候,能够抉择哈希索引,查问性能最快;其余大部分场景,倡议抉择 BTree 索引。

  • B 树索引

mysql 通过存储引擎取数据,基本上 90% 的人用的就是 InnoDB 了,依照实现形式分,InnoDB 的索引类型目前只有两种:BTREE(B 树)索引和 HASH 索引。B 树索引是 Mysql 数据库中应用最频繁的索引类型,根本所有存储引擎都反对 BTree 索引。通常咱们说的索引不出意外指的就是(B 树)索引(理论是用 B + 树实现的,因为在查看表索引时,mysql 一律打印 BTREE,所以简称为 B 树索引)

查问形式

  • 主键索引区:PI(关联保留的时数据的地址)按主键查问,
  • 一般索引区:si(关联的 id 的地址, 而后再达到下面的地址)。所以按主键查问, 速度最快

B+tree 性质

  • 1.)n 棵子 tree 的节点蕴含 n 个关键字,不用来保留数据而是保留数据的索引。
  • 2.)所有的叶子结点中蕴含了全副关键字的信息,及指向含这些关键字记录的指针,且叶子结点自身依关键字的大小自小而大程序链接。
  • 3.)所有的非终端结点能够看成是索引局部,结点中仅含其子树中的最大(或最小)关键字。
  • 4.)B+ 树中,数据对象的插入和删除仅在叶节点上进行。
  • 5.)B+ 树有 2 个头指针,一个是树的根节点,一个是最小关键码的叶节点。
  • 哈希索引

简要说下,相似于数据结构中简略实现的 HASH 表(散列表)一样,当咱们在 mysql 中用哈希索引时,次要就是通过 Hash 算法(常见的 Hash 算法有间接定址法、平方取中法、折叠法、除数取余法、随机数法),将数据库字段数据转换成定长的 Hash 值,与这条数据的行指针一并存入 Hash 表的对应地位;如果产生 Hash 碰撞(两个不同关键字的 Hash 值雷同),则在对应 Hash 键下以链表模式存储。当然这只是简略模仿图。

索引的基本原理

索引用来疾速地寻找那些具备特定值的记录。如果没有索引,一般来说执行查问时遍历整张表。

索引的原理很简略,就是把无序的数据变成有序的查问

  • 把创立了索引的列的内容进行排序
  • 对排序后果生成倒排表
  • 在倒排表内容上拼上数据地址链
  • 在查问的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
索引算法有哪些?

索引算法有BTree 算法和 Hash 算法

  • BTree 算法

BTree 是最罕用的 mysql 数据库索引算法,也是 mysql 默认的算法。因为它不仅能够被用在 =,>,>=,<,<= 和 between 这些比拟操作符上,而且还能够用于 like 操作符,只有它的查问条件是一个不以通配符结尾的常量,例如:

-- 只有它的查问条件是一个不以通配符结尾的常量
select * from user where name like 'jack%'; 
-- 如果一通配符结尾,或者没有应用常量,则不会应用索引,例如:select * from user where name like '%jack'; 
  • Hash 算法

Hash Hash 索引只能用于对等比拟,例如 =,<=>(相当于 =)操作符。因为是一次定位数据,不像 BTree 索引须要从根节点到枝节点,最初能力拜访到页节点这样屡次 IO 拜访,所以检索效率远高于 BTree 索引。

索引设计的准则?
  • 适宜索引的列是呈现在 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 的数据类型的列不要建设索引。
创立索引的三种形式,删除索引
  • 第一种形式:在执行 CREATE TABLE 时创立索引

    CREATE TABLE user_index2 (
      id INT auto_increment PRIMARY KEY,
      first_name VARCHAR (16),
      last_name VARCHAR (16),
      id_card VARCHAR (18),
      information text,
      KEY name (first_name, last_name),
      FULLTEXT KEY (information),
      UNIQUE KEY (id_card)
    );
  • 第二种形式:应用 ALTER TABLE 命令去减少索引

    ALTER TABLE table_name ADD INDEX index_name (column_list);
  • ALTER TABLE 用来创立一般索引、UNIQUE 索引或 PRIMARY KEY 索引。
  • 其中 table_name 是要减少索引的表名,column_list 指出对哪些列进行索引,多列时各列之间用逗号分隔。
  • 索引名 index_name 可本人命名,缺省时,MySQL 将依据第一个索引列赋一个名称。另外,ALTER TABLE 容许在单个语句中更改多个表,因而能够在同时创立多个索引。
  • 第三种形式:应用 CREATE INDEX 命令创立

    CREATE INDEX index_name ON table_name (column_list);

    CREATE INDEX 可对表减少一般索引或 UNIQUE 索引。(然而,不能创立 PRIMARY KEY 索引)

删除索引

依据索引名删除一般索引、惟一索引、全文索引:alter table 表名 drop KEY 索引名

alter table user_index drop KEY name;
alter table user_index drop KEY id_card;
alter table user_index drop KEY information;

删除主键索引:alter table 表名 drop primary key(因为主键只有一个)。这里值得注意的是,如果主键自增长,那么不能间接执行此操作(自增长依赖于主键索引):

须要勾销自增长再行删除:

alter table user_index
-- 从新定义字段
MODIFY id int,
drop PRIMARY KEY

但通常不会删除主键,因为设计主键肯定与业务逻辑无关。

创立索引时须要留神什么?
  • 非空字段:应该指定列为 NOT NULL,除非你想存储 NULL。在 mysql 中,含有空值的列很难进行查问优化,因为它们使得索引、索引的统计信息以及比拟运算更加简单。你应该用 0、一个非凡的值或者一个空串代替空值;
  • 取值离散大的字段:(变量各个取值之间的差别水平)的列放到联结索引的后面,能够通过 count()函数查看字段的差别值,返回值越大阐明字段的惟一值越多字段的离散水平高;
  • 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次 IO 操作获取的数据越大效率越高。
应用索引查问肯定能进步查问的性能吗?为什么

通常,通过索引查问数据比全表扫描要快。然而咱们也必须留神到它的代价。

  • 索引须要空间来存储,也须要定期维护,每当有记录在表中增减或索引列被批改时,索引自身也会被批改。这意味着每条记录的 INSERT,DELETE,UPDATE 将为此多付出 4,5 次的磁盘 I /O。因为索引须要额定的存储空间和解决,那些不必要的索引反而会使查问反应时间变慢。应用索引查问不肯定能进步查问性能,索引范畴查问 (INDEX RANGE SCAN) 实用于两种状况:
  • 基于一个范畴的检索,个别查问返回后果集小于表中记录数的 30%
  • 基于非唯一性索引的检索
百万级别或以上的数据如何删除

对于索引:因为索引须要额定的保护老本,因为索引文件是独自存在的文件, 所以当咱们对数据的减少, 批改, 删除, 都会产生额定的对索引文件的操作, 这些操作须要耗费额定的 IO, 会升高增 / 改 / 删的执行效率。所以,在咱们删除数据库百万级别数据的时候,查问 MySQL 官网手册得悉删除数据的速度和创立的索引数量是成正比的。

  • 所以咱们想要删除百万数据的时候能够先删除索引(此时大略耗时三分多钟)
  • 而后删除其中无用数据(此过程须要不到两分钟)
  • 删除实现后从新创立索引 (此时数据较少了) 创立索引也十分快,约十分钟左右。
  • 与之前的间接删除相对是要疾速很多,更别说万一删除中断, 所有删除会回滚。那更是坑了。
前缀索引

语法:index(field(10)),应用字段值的前 10 个字符建设索引,默认是应用字段的全部内容建设索引。

前提:前缀的标识度高。比方明码就适宜建设前缀索引,因为明码简直各不相同。

实操的难度:在于前缀截取的长度。

咱们能够利用select count(*)/count(distinct left(password,prefixLen));,通过从调整 prefixLen 的值(从 1 自增)查看不同前缀长度的一个均匀匹配度,靠近 1 时就能够了(示意一个明码的前 prefixLen 个字符简直能确定惟一一条记录)

什么是最左前缀准则?什么是最左匹配准则
  • 顾名思义,就是最左优先,在创立多列索引时,要依据业务需要,where 子句中应用最频繁的一列放在最右边。
  • 最左前缀匹配准则,十分重要的准则,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 的程序能够任意调整。
  • = 和 in 能够乱序,比方 a = 1 and b = 2 and c = 3 建设 (a,b,c) 索引能够任意程序,mysql 的查问优化器会帮你优化成索引能够辨认的模式

B 树和 B + 树的区别

在 B 树中,你能够将键和值寄存在外部节点和叶子节点;但在 B + 树中,外部节点都是键,没有值,叶子节点同时寄存键和值。

B+ 树的叶子节点有一条链相连,而 B 树的叶子节点各自独立。

应用 B 树的益处

B 树能够在外部节点同时存储键和值,因而,把频繁拜访的数据放在凑近根节点的中央将会大大提高热点数据的查问效率。这种个性使得 B 树在特定数据反复屡次查问的场景中更加高效。

应用 B + 树的益处

因为 B + 树的外部节点只寄存键,不寄存值,因而,一次读取,能够在内存页中获取更多的键,有利于更快地放大查找范畴。B+ 树的叶节点由一条链相连,因而,当须要进行一次全数据遍历的时候,B+ 树只须要应用 O(logN)工夫找到最小的一个节点,而后通过链进行 O(N)的程序遍历即可。而 B 树则须要对树的每一层进行遍历,这会须要更多的内存置换次数,因而也就须要破费更多的工夫

Hash 索引和 B + 树所有有什么区别或者说优劣呢?

首先要晓得 Hash 索引和 B + 树索引的底层实现原理:

hash 索引底层就是 hash 表,进行查找时,调用一次 hash 函数就能够获取到相应的键值,之后进行回表查问取得理论数据。B+ 树底层实现是多路均衡查找树。对于每一次的查问都是从根节点登程,查找到叶子节点方能够取得所查键值,而后依据查问判断是否须要回表查问数据。

那么能够看出他们有以下的不同:

  • hash 索引进行等值查问更快(个别状况下),然而却无奈进行范畴查问。

因为在 hash 索引中通过 hash 函数建设索引之后,索引的程序与原程序无奈保持一致,不能反对范畴查问。而 B + 树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也相似),人造反对范畴。

hash 索引不反对应用索引进行排序,原理同上。

  • hash 索引不反对含糊查问以及多列索引的最左前缀匹配。原理也是因为 hash 函数的不可预测。AAAA 和 AAAAB 的索引没有相关性。
  • hash 索引任何时候都防止不了回表查问数据,而 B + 树在合乎某些条件 (聚簇索引,笼罩索引等) 的时候能够只通过索引实现查问。
  • hash 索引尽管在等值查问上较快,然而不稳固。性能不可预测,当某个键值存在大量反复的时候,产生 hash 碰撞,此时效率可能极差。而 B + 树的查问效率比较稳定,对于所有的查问都是从根节点到叶子节点,且树的高度较低。

因而,在大多数状况下,间接抉择 B + 树索引能够取得稳固且较好的查问速度。而不须要应用 hash 索引。

数据库为什么应用 B + 树而不是 B 树
  • B 树只适宜随机检索,而 B + 树同时反对随机检索和程序检索;
  • B+ 树空间利用率更高,可缩小 I / O 次数,磁盘读写代价更低。一般来说,索引自身也很大,不可能全副存储在内存中,因而索引往往以索引文件的模式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘 I / O 耗费。B+ 树的外部结点并没有指向关键字具体信息的指针,只是作为索引应用,其外部结点比 B 树小,盘块能包容的结点中关键字数量更多,一次性读入内存中能够查找的关键字也就越多,绝对的,IO 读写次数也就升高了。而 IO 读写次数是影响索引检索效率的最大因素;
  • B+ 树的查问效率更加稳固。B 树搜寻有可能会在非叶子结点完结,越凑近根节点的记录查找时间越短,只有找到关键字即可确定记录的存在,其性能等价于在关键字选集内做一次二分查找。而在 B + 树中,程序检索比拟显著,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有关键字的查找门路长度雷同,导致每一个关键字的查问效率相当。
  • B- 树在进步了磁盘 IO 性能的同时并没有解决元素遍历的效率低下的问题。B+ 树的叶子节点应用指针程序连贯在一起,只有遍历叶子节点就能够实现整棵树的遍历。而且在数据库中基于范畴的查问是十分频繁的,而 B 树不反对这样的操作。
  • 增删文件(节点)时,效率更高。因为 B + 树的叶子节点蕴含所有关键字,并以有序的链表构造存储,这样可很好进步增删效率。
B+ 树在满足聚簇索引和笼罩索引的时候不须要回表查问数据,

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

当查问应用聚簇索引时,在对应的叶子节点,能够获取到整行数据,因而不必再次进行回表查问。

什么是聚簇索引?何时应用聚簇索引与非聚簇索引
  • 聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
  • 非聚簇索引:将数据存储于索引离开构造,索引构造的叶子节点指向了数据的对应行,myisam 通过 key_buffer 把索引先缓存到内存中,当须要拜访数据时(通过索引拜访数据),在内存中间接搜寻索引,而后通过索引找到磁盘相应数据,这也就是为什么索引不在 key buffer 命中时,速度慢的起因

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

何时应用聚簇索引与非聚簇索引

非聚簇索引肯定会回表查问吗?

不肯定,这波及到查问语句所要求的字段是否全副命中了索引,如果全副命中了索引,那么就不用再进行回表查问。

举个简略的例子,假如咱们在员工表的年龄上建设了索引,那么当进行 select age from employee where age < 20 的查问时,在索引的叶子节点上,曾经蕴含了 age 信息,不会再次进行回表查问。

联结索引是什么?为什么须要留神联结索引中的程序?

MySQL 能够应用多个字段同时建设一个索引,叫做联结索引。在联结索引中,如果想要命中索引,须要依照建设索引时的字段程序挨个应用,否则无奈命中索引。

具体起因为:

MySQL 应用索引时须要索引有序,假如当初建设了 ”name,age,school” 的联结索引,那么索引的排序为: 先依照 name 排序,如果 name 雷同,则依照 age 排序,如果 age 的值也相等,则依照 school 进行排序。

当进行查问时,此时索引仅仅依照 name 严格有序,因而必须首先应用 name 字段进行等值查问,之后对于匹配到的列而言,其依照 age 字段严格有序,此时能够应用 age 字段用做索引查找,以此类推。因而在建设联结索引的时候应该留神索引列的程序,个别状况下,将查问需要频繁或者字段选择性高的列放在后面。此外能够依据特例的查问或者表构造进行独自的调整。

事务

什么是数据库事务?

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

事务最经典也常常被拿出来说例子就是转账了。

如果小明要给小红转账 1000 元,这个转账会波及到两个要害操作就是:将小明的余额缩小 1000 元,将小红的余额减少 1000 元。万一在这两个操作之间忽然呈现谬误比方银行零碎解体,导致小明余额缩小而小红的余额没有减少,这样就不对了。事务就是保障这两个要害操作要么都胜利,要么都要失败。

事物的四大个性 (ACID) 介绍一下?

关系性数据库须要遵循 ACID 规定,具体内容如下:

  • 原子性:事务是最小的执行单位,不容许宰割。事务的原子性确保动作要么全副实现,要么齐全不起作用;
  • 一致性:执行事务前后,数据保持一致,多个事务对同一个数据读取的后果是雷同的;
  • 隔离性:并发拜访数据库时,一个用户的事务不被其余事务所烦扰,各并发事务之间数据库是独立的;
  • 持久性:一个事务被提交之后。它对数据库中数据的扭转是长久的,即便数据库产生故障也不应该对其有任何影响。
什么是脏读?幻读?不可反复读?

脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,因为某些起因,前一个 RollBack 了操作,则后一个事务所读取的数据就会是不正确的。

不可反复读(Non-repeatable read): 在一个事务的两次查问之中数据不统一,这可能是两次查问过程两头插入了一个事务更新的原有的数据。

幻读 (Phantom Read): 在一个事务的两次查问中数据笔数不统一,例如有一个事务查问了几列(Row) 数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查问中,就会发现有几列数据是它先前所没有的。

什么是事务的隔离级别?MySQL 的默认隔离级别是什么?

为了达到事务的四大个性,数据库定义了 4 种不同的事务隔离级别,由低到高顺次为 Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别能够一一解决脏读、不可反复读、幻读这几类问题。

SQL 规范定义了四个隔离级别:

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,容许读取尚未提交的数据变更,可能会导致脏读、幻读或不可反复读。
  • READ-COMMITTED(读取已提交):容许读取并发事务曾经提交的数据,能够阻止脏读,然而幻读或不可反复读仍有可能产生。
  • REPEATABLE-READ(可反复读):对同一字段的屡次读取后果都是统一的,除非数据是被自身事务本人所批改,能够阻止脏读和不可反复读,但幻读仍有可能产生。
  • SERIALIZABLE(可串行化):最高的隔离级别,齐全遵从 ACID 的隔离级别。所有的事务顺次一一执行,这样事务之间就齐全不可能产生烦扰,也就是说,该级别能够避免脏读、不可反复读以及幻读。

这里须要留神的是:Mysql 默认采纳的 REPEATABLE_READ 隔离级别 Oracle 默认采纳的 READ_COMMITTED 隔离级别

事务隔离机制的实现基于锁机制和并发调度。其中并发调度应用的是 MVVC(多版本并发管制),通过保留批改的旧版本信息来反对并发一致性读和回滚等个性。

因为隔离级别越低,事务申请的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容):,然而你要晓得的是 InnoDB 存储引擎默认应用 REPEATABLE-READ(可重读)并不会有任何性能损失。

InnoDB 存储引擎在 分布式事务 的状况下个别会用到 SERIALIZABLE(可串行化) 隔离级别。

对 MySQL 的锁理解吗

当数据库有并发事务的时候,可能会产生数据的不统一,这时候须要一些机制来保障拜访的秩序,锁机制就是这样的一个机制。

就像酒店的房间,如果大家随便进出,就会呈现多人争夺同一个房间的状况,而在房间上装上锁,申请到钥匙的人才能够入住并且将房间锁起来,其他人只有等他应用结束才能够再次应用。

隔离级别与锁的关系

在 Read Uncommitted 级别下,读取数据不须要加共享锁,这样就不会跟被批改的数据上的排他锁抵触

在 Read Committed 级别下,读操作须要加共享锁,然而在语句执行完当前开释共享锁;

在 Repeatable Read 级别下,读操作须要加共享锁,然而在事务提交之前并不开释共享锁,也就是必须期待事务执行结束当前才开释共享锁。

SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范畴的键,并始终持有锁,直到事务实现。

依照锁的粒度分数据库锁有哪些?锁机制与 InnoDB 锁算法

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

MyISAM 和 InnoDB 存储引擎应用的锁:
  • MyISAM 采纳表级锁(table-level locking)。
  • InnoDB 反对行级锁 (row-level locking) 和表级锁,默认为行级锁

行级锁,表级锁和页级锁比照

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

特点:开销大,加锁慢;会呈现死锁;锁定粒度最小,产生锁抵触的概率最低,并发度也最高。

表级锁 是 MySQL 中锁定粒度最大的一种锁,示意对以后操作的整张表加锁,它实现简略,资源耗费较少,被大部分 MySQL 引擎反对。最常应用的 MYISAM 与 INNODB 都反对表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。

特点:开销小,加锁快;不会呈现死锁;锁定粒度大,收回锁抵触的概率最高,并发度最低。

页级锁 是 MySQL 中锁定粒度介于行级锁和表级锁两头的一种锁。表级锁速度快,但抵触多,行级抵触少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。

特点:开销和加锁工夫界于表锁和行锁之间;会呈现死锁;锁定粒度界于表锁和行锁之间,并发度个别

从锁的类别上分 MySQL 都有哪些锁呢?像下面那样子进行锁定岂不是有点妨碍并发效率了

从锁的类别上来讲,有共享锁和排他锁。

共享锁: 又叫做读锁。当用户要进行数据的读取时,对数据加上共享锁。共享锁能够同时加上多个。

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

用下面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是能够承受的。一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不能够。

锁的粒度取决于具体的存储引擎,InnoDB 实现了行级锁,页级锁,表级锁。

他们的加锁开销从大到小,并发能力也是从大到小。

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

答:InnoDB 是基于索引来实现行锁

例: select * from tab_with_index where id = 1 for update;

for update 能够依据条件来实现行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么 InnoDB 将实现表锁,并发将无从谈起

InnoDB 存储引擎的锁的算法有三种
  • Record lock:单个行记录上的锁
  • Gap lock:间隙锁,锁定一个范畴,不包含记录自身
  • Next-key lock:record+gap 锁定一个范畴,蕴含记录自身
相干知识点:
  • innodb 对于行的查问应用 next-key lock
  • Next-locking keying 为了解决 Phantom Problem 幻读问题
  • 当查问的索引含有惟一属性时,将 next-key lock 降级为 record key
  • Gap 锁设计的目标是为了阻止多个事务将记录插入到同一范畴内,而这会导致幻读问题的产生
  • 有两种形式显式敞开 gap 锁:(除了外键束缚和唯一性查看外,其余状况仅应用 record lock)A. 将事务隔离级别设置为 RC B. 将参数 innodb_locks_unsafe_for_binlog 设置为 1
什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上互相占用,并申请锁定对方的资源,从而导致恶性循环的景象。

常见的解决死锁的办法

  • 1、如果不同程序会并发存取多个表,尽量约定以雷同的程序拜访表,能够大大降低死锁机会。
  • 2、在同一个事务中,尽可能做到一次锁定所须要的所有资源,缩小死锁产生概率;
  • 3、对于非常容易产生死锁的业务局部,能够尝试应用降级锁定颗粒度,通过表级锁定来缩小死锁产生的概率;

如果业务解决不好能够用分布式事务锁或者应用乐观锁

数据库的乐观锁和乐观锁是什么?怎么实现的?

数据库管理系统(DBMS)中的并发管制的工作是确保在多个事务同时存取数据库中同一数据时不毁坏事务的隔离性和统一性以及数据库的统一性。乐观并发管制(乐观锁)和乐观并发管制(乐观锁)是并发管制次要采纳的技术手段。

乐观锁:假设会产生并发抵触,屏蔽所有可能违反数据完整性的操作。在查问完数据的时候就把事务锁起来,直到提交事务。实现形式:应用数据库中的锁机制

乐观锁:假如不会产生并发抵触,只在提交操作时查看是否违反数据完整性。在批改数据的时候把事务锁起来,通过 version 的形式来进行锁定。实现形式:乐个别会应用版本号机制或 CAS 算法实现。

两种锁的应用场景

从上面对两种锁的介绍,咱们晓得两种锁各有优缺点,不可认为一种好于另一种,像乐观锁实用于写比拟少的状况下(多读场景),即抵触真的很少产生的时候,这样能够省去了锁的开销,加大了零碎的整个吞吐量。

但如果是多写的状况,个别会常常产生抵触,这就会导致下层利用会一直的进行 retry,这样反倒是升高了性能,所以个别多写的场景下用乐观锁就比拟适合。

视图

为什么要应用视图?什么是视图?

为了进步简单 SQL 语句的复用性和表操作的安全性,MySQL 数据库管理系统提供了视图个性。所谓视图,实质上是一种虚构表,在物理上是不存在的,其内容与实在的表类似,蕴含一系列带有名称的列和行数据。然而,视图并不在数据库中以贮存的数据值模式存在。行和列数据来自定义视图的查问所援用根本表,并且在具体援用视图时动静生成。

视图使开发者只关怀感兴趣的某些特定数据和所负责的特定工作,只能看到视图中所定义的数据,而不是视图所援用表中的数据,从而进步了数据库中数据的安全性。

视图有哪些特点?

视图的特点如下:

  • 视图的列能够来自不同的表,是表的形象和在逻辑意义上建设的新关系。
  • 视图是由根本表 (实表) 产生的表(虚表)。
  • 视图的建设和删除不影响根本表。
  • 对视图内容的更新 (增加,删除和批改) 间接影响根本表。
  • 当视图来自多个根本表时,不容许增加和删除数据。

视图的操作包含创立视图,查看视图,删除视图和批改视图。

视图的应用场景有哪些?

视图基本用处:简化 sql 查问,进步开发效率。如果说还有另外一个用处那就是兼容老的表构造。

上面是视图的常见应用场景:

  • 重用 SQL 语句;
  • 简化简单的 SQL 操作。在编写查问后,能够不便的重用它而不用晓得它的根本查问细节;
  • 应用表的组成部分而不是整个表;
  • 爱护数据。能够给用户授予表的特定局部的拜访权限而不是整个表的拜访权限;
  • 更改数据格式和示意。视图可返回与底层表的示意和格局不同的数据。
视图的长处
  • 查问简单化。视图能简化用户的操作
  • 数据安全性。视图使用户能以多种角度对待同一数据,可能对秘密数据提供平安爱护
  • 逻辑数据独立性。视图对重构数据库提供了肯定水平的逻辑独立性
视图的毛病

性能。数据库必须把视图的查问转化成对根本表的查问,如果这个视图是由一个简单的多表查问所定义,那么,即便是视图的一个简略查问,数据库也把它变成一个简单的结合体,须要破费肯定的工夫。

批改限度。当用户试图批改视图的某些行时,数据库必须把它转化为对根本表的某些行的批改。事实上,当从视图中插入或者删除时,状况也是这样。对于简略视图来说,这是很不便的,然而,对于比较复杂的视图,可能是不可批改的

这些视图有如下特色:1. 有 UNIQUE 等汇合操作符的视图。2. 有 GROUP BY 子句的视图。3. 有诸如 AVG\SUM\MAX 等聚合函数的视图。4. 应用 DISTINCT 关键字的视图。5. 连贯表的视图(其中有些例外)

什么是游标?

游标是零碎为用户开设的一个数据缓冲区,寄存 SQL 语句的执行后果,每个游标区都有一个名字。用户能够通过游标逐个获取记录并赋给主变量,交由主语言进一步解决。

存储过程与函数

什么是存储过程?有哪些优缺点?

存储过程是一个预编译的 SQL 语句,长处是容许模块化的设计,就是说只须要创立一次,当前在该程序中就能够调用屡次。如果某次操作须要执行屡次 SQL,应用存储过程比单纯 SQL 语句执行要快。

长处

  • 1)存储过程是预编译过的,执行效率高。
  • 2)存储过程的代码间接寄存于数据库中,通过存储过程名间接调用,缩小网络通讯。
  • 3)安全性高,执行存储过程须要有肯定权限的用户。
  • 4)存储过程能够重复使用,缩小数据库开发人员的工作量。

毛病

  • 1)调试麻烦,然而用 PL/SQL Developer 调试很不便!补救这个毛病。
  • 2)移植问题,数据库端代码当然是与数据库相干的。然而如果是做工程型我的项目,根本不存在移植问题。
  • 3)从新编译问题,因为后端代码是运行前编译的,如果带有援用关系的对象产生扭转时,受影响的存储过程、包将须要从新编译(不过也能够设置成运行时刻主动编译)。
  • 4)如果在一个程序零碎中大量的应用存储过程,到程序交付使用的时候随着用户需要的减少会导致数据结构的变动,接着就是零碎的相干问题了,最初如果用户想保护该零碎能够说是很难很难、而且代价是空前的,保护起来更麻烦。

触发器

什么是触发器?触发器的应用场景有哪些?

触发器是用户定义在关系表上的一类由事件驱动的非凡的存储过程。触发器是指一段代码,当触发某个事件时,主动执行这些代码。

应用场景
  • 能够通过数据库中的相干表实现级联更改。
  • 实时监控某张表中的某个字段的更改而须要做出相应的解决。
  • 例如能够生成某些业务的编号。

留神不要滥用,否则会造成数据库及应用程序的保护艰难。

大家须要牢记以上根底知识点,重点是了解数据类型 CHAR 和 VARCHAR 的差别,表存储引擎 InnoDB 和 MyISAM 的区别。

MySQL 中都有哪些触发器?

在 MySQL 数据库中有如下六种触发器:

  • Before Insert
  • After Insert
  • Before Update
  • After Update
  • Before Delete
  • After Delete

罕用 SQL 语句

SQL 语句次要分为哪几类

数据定义语言 DDL(Data Ddefinition Language)CREATE,DROP,ALTER

次要为以上操作 即对逻辑构造等有操作的,其中包含表构造,视图和索引。

数据查询语言 DQL(Data Query Language)SELECT

这个较为好了解 即查问操作,以 select 关键字。各种简略查问,连贯查问等 都属于 DQL。

数据操纵语言 DML(Data Manipulation Language)INSERT,UPDATE,DELETE

次要为以上操作 即对数据进行操作的,对应下面所说的查问操作 DQL 与 DML 独特构建了少数高级程序员罕用的增删改查操作。而查问是较为非凡的一种 被划分到 DQL 中。

数据管制性能 DCL(Data Control Language)GRANT,REVOKE,COMMIT,ROLLBACK

次要为以上操作 即对数据库安全性完整性等有操作的,能够简略的了解为权限管制等。

超键、候选键、主键、外键别离是什么?
  • 超键:在关系中能惟一标识元组的属性集称为关系模式的超键。一个属性能够为作为一个超键,多个属性组合在一起也能够作为一个超键。超键蕴含候选键和主键。
  • 候选键:是最小超键,即没有冗余元素的超键。
  • 主键:数据库表中对贮存数据对象予以惟一和残缺标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
  • 外键:在一个表中存在的另一个表的主键称此表的外键。
SQL 束缚有哪几种?
  • NOT NULL: 用于管制字段的内容肯定不能为空(NULL)。
  • UNIQUE: 控件字段内容不能反复,一个表容许有多个 Unique 束缚。
  • PRIMARY KEY: 也是用于控件字段内容不能反复,但它在一个表只容许呈现一个。
  • FOREIGN KEY: 用于预防毁坏表之间连贯的动作,也能避免非法数据插入外键列,因为它必须是它指向的那个表中的值之一。
  • CHECK: 用于管制字段的值范畴。
六种关联查问
  • i 穿插连贯(CROSS JOIN)
  • i 内连贯(INNER JOIN)
  • i 外连贯(LEFT JOIN/RIGHT JOIN)
  • i 联结查问(UNION 与 UNION ALL)
  • i 全连贯(FULL JOIN)
  • i 穿插连贯(CROSS JOIN)

    SELECT * FROM A,B(,C)或者 SELECT * FROM A CROSS JOIN B (CROSS JOIN C)# 没有任何关联条件,后果是笛卡尔积,后果集会很大,没有意义,很少应用内连贯(INNER JOIN)SELECT * FROM A,B WHERE A.id=B.id 或者 SELECT * FROM A INNER JOIN B ON A.id=B.id 多表中同时合乎某种条件的数据记录的汇合,INNER JOIN 能够缩写为 JOIN

    内连贯分为三类

  • 等值连贯:ON A.id=B.id
  • 不等值连贯:ON A.id > B.id
  • 自连贯:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid

外连贯(LEFT JOIN/RIGHT JOIN)

  • 左外连贯:LEFT OUTER JOIN, 以左表为主,先查问出左表,依照 ON 后的关联条件匹配右表,没有匹配到的用 NULL 填充,能够简写成 LEFT JOIN
  • 右外连贯:RIGHT OUTER JOIN, 以右表为主,先查问出右表,依照 ON 后的关联条件匹配左表,没有匹配到的用 NULL 填充,能够简写成 RIGHT JOIN

联结查问(UNION 与 UNION ALL)

SELECT * FROM A UNION SELECT * FROM B UNION ...
  • 就是把多个后果集集中在一起,UNION 前的后果为基准,须要留神的是联结查问的列数要相等,雷同的记录行会合并
  • 如果应用 UNION ALL,不会合并反复的记录行
  • 效率 UNION 高于 UNION ALL

全连贯(FULL JOIN)

  • MySQL 不反对全连贯
  • 能够应用 LEFT JOIN 和 UNION 和 RIGHT JOIN 联结应用

    SELECT * FROM A LEFT JOIN B ON A.id=B.id UNIONSELECT * FROM A RIGHT JOIN B ON A.id=B.id

    表连贯面试题

有 2 张表,1 张 R、1 张 S,R 表有 ABC 三列,S 表有 CD 两列,表中各有三条记录。

# 穿插连贯(笛卡尔积):

select r.*,s.* from r,s

内连贯后果:

select r.*,s.* from r inner join s on r.c=s.c

左连贯后果:

select r.*,s.* from r left join s on r.c=s.c

右连贯后果:

select r.*,s.* from r right join s on r.c=s.c

全表连贯的后果(MySql 不反对,Oracle 反对):

select r.*,s.* from r full join s on r.c=s.c

什么是子查问

条件:一条 SQL 语句的查问后果做为另一条查问语句的条件或查问后果

嵌套:多条 SQL 语句嵌套应用,外部的 SQL 查问语句称为子查问。

子查问的三种状况

子查问是单行单列的状况:后果集是一个值,父查问应用:=、<、> 等运算符

-- 查问工资最高的员工是谁?select  * from employee where salary=(select max(salary) from employee);   

子查问是多行单列的状况:后果集相似于一个数组,父查问应用:in 运算符

-- 查问工资最高的员工是谁?select  * from employee where salary=(select max(salary) from employee);    

子查问是多行多列的状况:后果集相似于一张虚构表,不能用于 where 条件,用于 select 子句中做为子表

-- 1) 查问出 2011 年当前入职的员工信息
-- 2) 查问所有的部门信息,与下面的虚构表中的信息比对,找出所有部门 ID 相等的员工。select * from dept d,  (select * from employee where join_date > '2011-1-1') e where e.dept_id =  d.id;    

-- 应用表连贯:select d.*, e.* from  dept d inner join employee e on d.id = e.dept_id where e.join_date >  '2011-1-1'  
mysql 中 in 和 exists 区别

mysql 中的 in 语句是把表面和内表作 hash 连贯,而 exists 语句是对表面作 loop 循环,每次 loop 循环再对内表进行查问。始终大家都认为 exists 比 in 语句的效率要高,这种说法其实是不精确的。这个是要辨别环境的。

  • 如果查问的两个表大小相当,那么用 in 和 exists 差异不大。
  • 如果两个表中一个较小,一个是大表,则子查问表大的用 exists,子查问表小的用 in。
  • not in 和 not exists:如果查问语句应用了 not in,那么内表面都进行全表扫描,没有用到索引;而 not extsts 的子查问仍然能用到表上的索引。所以无论那个表大,用 not exists 都比 not in 要快。
varchar 与 char 的区别
  • char 的特点

    • char 示意定长字符串,长度是固定的;
    • 如果插入数据的长度小于 char 的固定长度时,则用空格填充;
    • 因为长度固定,所以存取速度要比 varchar 快很多,甚至能快 50%,但正因为其长度固定,所以会占据多余的空间,是空间换工夫的做法;
    • 对于 char 来说,最多能寄存的字符个数为 255,和编码无关
  • varchar 的特点

    • varchar 示意可变长字符串,长度是可变的;
    • 插入的数据是多长,就依照多长来存储;
    • varchar 在存取方面与 char 相同,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是工夫换空间的做法;
    • 对于 varchar 来说,最多能寄存的字符个数为 65532

总之,联合性能角度(char 更快)和节俭磁盘空间角度(varchar 更小),具体情况还需具体来设计数据库才是得当的做法。

varchar(50)中 50 的涵义

最多寄存 50 个字符,varchar(50)和 (200) 存储 hello 所占空间一样,但后者在排序时会耗费更多内存,因为 order by col 采纳 fixed_length 计算 col 长度(memory 引擎也一样)。在晚期 MySQL 版本中,50 代表字节数,当初代表字符数。

int(20)中 20 的涵义

是指显示字符的长度。20 示意最大显示宽度为 20,但仍占 4 字节存储,存储范畴不变;

不影响外部存储,只是影响带 zerofill 定义的 int 时,后面补多少个 0,易于报表展现

mysql 为什么这么设计

对大多数利用没有意义,只是规定一些工具用来显示字符的个数;int(1)和 int(20)存储和计算均一样;

mysql 中 int(10)和 char(10)以及 varchar(10)的区别

  • int(10)的 10 示意显示的数据的长度,不是存储数据的大小;chart(10)和 varchar(10)的 10 示意存储数据的大小,即示意存储多少个字符。
  • int(10) 10 位的数据长度 9999999999,占 32 个字节,int 型 4 位
  • char(10) 10 位固定字符串,有余补空格 最多 10 个字符
  • varchar(10) 10 位可变字符串,有余补空格 最多 10 个字符
  • char(10)示意存储定长的 10 个字符,有余 10 个就用空格补齐,占用更多的存储空间
  • varchar(10)示意存储 10 个变长的字符,存储多少个就是多少个,空格也按一个字符存储,这一点是和 char(10)的空格不同的,char(10)的空格示意占位不算一个字符
FLOAT 和 DOUBLE 的区别是什么?
  • FLOAT 类型数据能够存储至少 8 位十进制数,并在内存中占 4 字节。
  • DOUBLE 类型数据能够存储至少 18 位十进制数,并在内存中占 8 字节。
drop、delete 与 truncate 的区别

三者都示意删除,然而三者有一些差异:

因而,在不再须要一张表的时候,用 drop;在想删除局部数据行时候,用 delete;在保留表而删除所有数据的时候用 truncate。

UNION 与 UNION ALL 的区别?
  • 如果应用 UNION ALL,不会合并反复的记录行
  • 效率 UNION 高于 UNION ALL

SQL 优化

如何定位及优化 SQL 语句的性能问题?创立的索引有没有被应用到? 或者说怎么才能够晓得这条语句运行很慢的起因?

对于低性能的 SQL 语句的定位,最重要也是最无效的办法就是应用执行打算,MySQL 提供了 explain 命令来查看语句的执行打算。咱们晓得,不论是哪种数据库,或者是哪种数据库引擎,在对一条 SQL 语句进行执行的过程中都会做很多相干的优化,对于查问语句,最重要的优化形式就是应用索引。而执行打算,就是显示数据库引擎对于 SQL 语句的执行的详细情况,其中蕴含了是否应用索引,应用什么索引,应用的索引的相干信息等。

执行打算蕴含的信息 id 有一组数字组成。示意一个查问中各个子查问的执行程序;

  • id 雷同执行程序由上至下。
  • id 不同,id 值越大优先级越高,越先被执行。
  • id 为 null 时示意一个后果集,不须要应用它查问,常呈现在蕴含 union 等查问语句中。

select_type 每个子查问的查问类型,一些常见的查问类型。

table 查问的数据表,当从衍生表中查数据时会显示 x 示意对应的执行打算 id partitions 表分区、表创立的时候能够指定通过那个列进行表分区。举个例子:

create table tmp (
    id int unsigned not null AUTO_INCREMENT,
    name varchar(255),
    PRIMARY KEY (id)
) engine = innodb
partition by key (id) partitions 5;

type(十分重要,能够看到有没有走索引) 拜访类型

  • ALL 扫描全表数据
  • index 遍历索引
  • range 索引范畴查找
  • index_subquery 在子查问中应用 ref
  • unique_subquery 在子查问中应用 eq_ref
  • ref_or_null 对 Null 进行索引的优化的 ref
  • fulltext 应用全文索引
  • ref 应用非惟一索引查找数据
  • eq_ref 在 join 查问中应用 PRIMARY KEYorUNIQUE NOT NULL 索引关联。

possible_keys 可能应用的索引,留神不肯定会应用。查问波及到的字段上若存在索引,则该索引将被列出来。当该列为 NULL 时就要思考以后的 SQL 是否须要优化了。

key 显示 MySQL 在查问中理论应用的索引,若没有应用索引,显示为 NULL。

TIPS: 查问中若应用了笼罩索引(笼罩索引:索引的数据笼罩了须要查问的所有数据),则该索引仅呈现在 key 列表中

key_length 索引长度

ref 示意上述表的连贯匹配条件,即哪些列或常量被用于查找索引列上的值

rows 返回估算的后果集数目,并不是一个精确的值。

extra 的信息十分丰盛,常见的有:

  • Using index 应用笼罩索引
  • Using where 应用了用 where 子句来过滤后果集
  • Using filesort 应用文件排序,应用非索引列进行排序时呈现,十分耗费性能,尽量优化。
  • Using temporary 应用了长期表 sql 优化的指标能够参考阿里开发手册

【举荐】SQL 性能优化的指标:至多要达到 range 级别,要求是 ref 级别,如果能够是 consts 最好。

阐明:

1)consts 单表中最多只有一个匹配行(主键或者惟一索引),在优化阶段即可读取到数据。2)ref 指的是应用一般的索引(normal index)。3)range 对索引进行范畴检索。反例:explain 表的后果,type=index,索引物理文件全扫描,速度十分慢,这个 index 级别比拟 range 还低,与全表扫描是小巫见大巫。

SQL 的生命周期?

  • 应用服务器与数据库服务器建设一个连贯
  • 数据库过程拿到申请 sql
  • 解析并生成执行打算,执行
  • 读取数据到内存并进行逻辑解决
  • 通过步骤一的连贯,发送后果到客户端
  • 关掉连贯,开释资源

大表数据查问,怎么优化
  • 优化 shema、sql 语句 + 索引;
  • 第二加缓存,memcached, redis;
  • 主从复制,读写拆散;
  • 垂直拆分,依据你模块的耦合度,将一个大的零碎分为多个小的零碎,也就是分布式系统;
  • 程度切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要抉择一个正当的 sharding key, 为了有好的查问效率,表构造也要改变,做肯定的冗余,利用也要改,sql 中尽量带 sharding key,将数据定位到限定的表下来查,而不是扫描全副的表;
超大分页怎么解决?

超大的分页个别从两个方向上来解决.

  • 数据库层面, 这也是咱们次要集中关注的 (尽管收效没那么大), 相似于select * from table where age > 20 limit 1000000,10 这种查问其实也是有能够优化的余地的. 这条语句须要 load1000000 数据而后基本上全副抛弃, 只取 10 条当然比较慢. 过后咱们能够批改为 select * from table where id in (select id from table where age > 20 limit 1000000,10). 这样尽管也 load 了一百万的数据, 然而因为索引笼罩, 要查问的所有字段都在索引中, 所以速度会很快. 同时如果 ID 间断的好, 咱们还能够 select * from table where id > 1000000 limit 10, 效率也是不错的, 优化的可能性有许多种, 然而核心思想都一样, 就是缩小 load 的数据.
  • 从需要的角度缩小这种申请…次要是不做相似的需要 (间接跳转到几百万页之后的具体某一页. 只容许逐页查看或者依照给定的路线走, 这样可预测, 可缓存) 以及避免 ID 透露且间断被人歹意攻打.

解决超大分页, 其实次要是靠缓存, 可预测性的提前查到内容, 缓存至 redis 等 k - V 数据库中, 间接返回即可.

在阿里巴巴《Java 开发手册》中, 对超大分页的解决办法是相似于下面提到的第一种.

【举荐】利用提早关联或者子查问优化超多分页场景。阐明:MySQL 并不是跳过 offset 行,而是取 offset+ N 行,而后返回放弃前 offset 行,返回 N 行,那当 offset 特地大的时候,效率就十分的低下,要么管制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。正例:先疾速定位须要获取的 id 段,而后再关联:SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20) b where a.id=b.id
mysql 分页

LIMIT 子句能够被用于强制 SELECT 语句返回指定的记录数。LIMIT 承受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)

mysql> SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15 

为了检索从某一个偏移量到记录集的完结所有的记录行,能够指定第二个参数为 -1:

mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. 

如果只给定一个参数,它示意返回最大的记录行数目:

mysql> SELECT * FROM table LIMIT 5; // 检索前 5 个记录行 

换句话说,LIMIT n 等价于 LIMIT 0,n。

慢查问日志

用于记录执行工夫超过某个临界值的 SQL 日志,用于疾速定位慢查问,为咱们的优化做参考。

开启慢查问日志

配置项: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 中

关怀过业务零碎外面的 sql 耗时吗?统计过慢查问吗?对慢查问都怎么优化过?

在业务零碎中,除了应用主键进行的查问,其余的我都会在测试库上测试其耗时,慢查问的统计次要由运维在做,会定期将业务中的慢查问反馈给咱们。

慢查问的优化首先要搞明确慢的起因是什么?是查问条件没有命中索引?是 load 了不须要的数据列?还是数据量太大?

所以优化也是针对这三个方向来的,

  • 首先剖析语句,看看是否 load 了额定的数据,可能是查问了多余的行并且摈弃掉了,可能是加载了许多后果中并不需要的列,对语句进行剖析以及重写。
  • 剖析语句的执行打算,而后取得其应用索引的状况,之后批改语句或者批改索引,使得语句能够尽可能的命中索引。
  • 如果对语句的优化曾经无奈进行,能够思考表中的数据量是否太大,如果是的话能够进行横向或者纵向的分表。
为什么要尽量设定一个主键?

主键是数据库确保数据行在整张表唯一性的保障,即便业务上本张表没有主键,也倡议增加一个自增长的 ID 列作为主键。设定了主键之后,在后续的删改查的时候可能更加疾速以及确保操作数据范畴平安。

主键应用自增 ID 还是 UUID?

举荐应用自增 ID,不要应用 UUID。

因为在 InnoDB 存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的 B + 树叶子节点上存储了主键索引以及全副的数据(依照程序),如果主键索引是自增 ID,那么只须要一直向后排列即可,如果是 UUID,因为到来的 ID 与原来的大小不确定,会造成十分多的数据插入,数据挪动,而后导致产生很多的内存碎片,进而造成插入性能的降落。

总之,在数据量大一些的状况下,用自增主键性能会好一些。

对于主键是聚簇索引,如果没有主键,InnoDB 会抉择一个惟一键来作为聚簇索引,如果没有惟一键,会生成一个隐式的主键。

字段为什么要求定义为 not null?

null 值会占用更多的字节,且会在程序中造成很多与预期不符的状况。

如果要存储用户的明码散列,应该应用什么字段进行存储?

明码散列,盐,用户身份证号等固定长度的字符串应该应用 char 而不是 varchar 来存储,这样能够节俭空间且进步检索效率。

优化查问过程中的数据拜访
  • 拜访数据太多导致查问性能降落
  • 确定应用程序是否在检索大量超过须要的数据,可能是太多行或列
  • 确认 MySQL 服务器是否在剖析大量不必要的数据行
  • 防止犯如下 SQL 语句谬误
  • 查问不须要的数据。解决办法:应用 limit 解决
  • 多表关联返回全部列。解决办法:指定列名
  • 总是返回全部列。解决办法:防止应用 SELECT *
  • 反复查问雷同的数据。解决办法:能够缓存数据,下次间接读取缓存
  • 是否在扫描额定的记录。解决办法:
  • 应用 explain 进行剖析,如果发现查问须要扫描大量的数据,但只返回多数的行,能够通过如下技巧去优化:
  • 应用索引笼罩扫描,把所有的列都放到索引中,这样存储引擎不须要回表获取对应行就能够返回后果。
  • 扭转数据库和表的构造,批改数据表范式
  • 重写 SQL 语句,让优化器能够以更优的形式执行查问。
优化长难的查问语句
  • 一个简单查问还是多个简略查问
  • MySQL 外部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多
  • 应用尽可能小的查问是好的,然而有时将一个大的查问合成为多个小的查问是很有必要的。
  • 切分查问
  • 将一个大的查问分为多个小的雷同的查问
  • 一次性删除 1000 万的数据要比一次删除 1 万,暂停一会的计划更加损耗服务器开销。
  • 合成关联查问,让缓存的效率更高。
  • 执行单个查问能够缩小锁的竞争。
  • 在应用层做关联更容易对数据库进行拆分。
  • 查问效率会有大幅晋升。
  • 较少冗余记录的查问。
优化特定类型的查问语句
  • count(*)会疏忽所有的列,间接统计所有列数,不要应用 count(列名)
  • MyISAM 中,没有任何 where 条件的 count(*)十分快。
  • 当有 where 条件时,MyISAM 的 count 统计不肯定比其它引擎快。
  • 能够应用 explain 查问近似值,用近似值代替 count(*)
  • 减少汇总表
  • 应用缓存
优化关联查问
  • 确定 ON 或者 USING 子句中是否有索引。
  • 确保 GROUP BY 和 ORDER BY 只有一个表中的列,这样 MySQL 才有可能应用索引。
优化子查问
  • 用关联查问代替
  • 优化 GROUP BY 和 DISTINCT
  • 这两种查问据能够应用索引来优化,是最无效的优化办法
  • 关联查问中,应用标识列分组的效率更高
  • 如果不须要 ORDER BY,进行 GROUP BY 时加 ORDER BY NULL,MySQL 不会再进行文件排序。
  • WITH ROLLUP 超级聚合,能够挪到利用程序处理
优化 LIMIT 分页
  • LIMIT 偏移量大的时候,查问效率较低
  • 能够记录上次查问的最大 ID,下次查问时间接依据该 ID 来查问
优化 UNION 查问
  • UNION ALL 的效率高于 UNION
优化 WHERE 子句

解题办法

对于此类考题,先阐明如何定位低效 SQL 语句,而后依据 SQL 语句可能低效的起因做排查,先从索引着手,如果索引没有问题,思考以上几个方面,数据拜访的问题,长难查问句的问题还是一些特定类型优化的问题,逐个答复。

SQL 语句优化的一些办法?
  • 1. 对查问进行优化,应尽量避免全表扫描,首先应思考在 where 及 order by 波及的列上建设索引。
  • 2. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃应用索引而进行全表扫描,如:

    select id from t where num is null
    -- 能够在 num 上设置默认值 0,确保表中 num 列没有 null 值,而后这样查问:select id from t where num=
  • 3. 应尽量避免在 where 子句中应用!= 或 <> 操作符,否则引擎将放弃应用索引而进行全表扫描。
  • 4. 应尽量避免在 where 子句中应用 or 来连贯条件,否则将导致引擎放弃应用索引而进行全表扫描,如:

    select id from t where num=10 or num=20
    -- 能够这样查问:select id from t where num=10 union all select id from t where num=2
  • 5.in 和 not in 也要慎用,否则会导致全表扫描,如:

    select id from t where num in(1,2,3) 
    -- 对于间断的数值,能用 between 就不要用 in 了:select id from t where num between 1 and 3
  • 6. 上面的查问也将导致全表扫描:select id from t where name like‘% 李 %’若要提高效率,能够思考全文检索。
  • 7. 如果在 where 子句中应用参数,也会导致全表扫描。因为 SQL 只有在运行时才会解析局部变量,但优化程序不能将拜访打算的抉择推延到运行时;它必须在编译时进行抉择。然 而,如果在编译时建设拜访打算,变量的值还是未知的,因此无奈作为索引抉择的输出项。如上面语句将进行全表扫描:

    select id from t where num=@num
    -- 能够改为强制查问应用索引:select id from t with(index(索引名)) where num=@num
  • 8. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃应用索引而进行全表扫描。如:

    select id from t where num/2=100
    -- 应改为:
    select id from t where num=100*2
  • 9. 应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃应用索引而进行全表扫描。如:

    select id from t where substring(name,1,3)=’abc’-- name 以 abc 结尾的 id 应改为:
    select id from t where name like‘abc%’
  • 10. 不要在 where 子句中的“=”右边进行函数、算术运算或其余表达式运算,否则零碎将可能无奈正确应用索引。

数据库优化

为什么要优化
  • 零碎的吞吐量瓶颈往往呈现在数据库的访问速度上
  • 随着应用程序的运行,数据库的中的数据会越来越多,解决工夫会相应变慢
  • 数据是寄存在磁盘上的,读写速度无奈和内存相比
  • 优化准则:缩小零碎瓶颈,缩小资源占用,减少零碎的反应速度。
数据库构造优化

一个好的数据库设计方案对于数据库的性能往往会起到事倍功半的成果。

须要思考数据冗余、查问和更新的速度、字段的数据类型是否正当等多方面的内容。

将字段很多的表分解成多个表

对于字段较多的表,如果有些字段的应用频率很低,能够将这些字段分离出来造成新表。

因为当一个表的数据量很大时,会因为应用频率低的字段的存在而变慢。

减少两头表

对于须要常常联结查问的表,能够建设两头表以进步查问效率。

通过建设两头表,将须要通过联结查问的数据插入到两头表中,而后将原来的联结查问改为对两头表的查问。

减少冗余字段

设计数据表时应尽量遵循范式实践的规约,尽可能的缩小冗余字段,让数据库设计看起来粗劣、优雅。然而,正当的退出冗余字段能够进步查问速度。

表的规范化水平越高,表和表之间的关系越多,须要连贯查问的状况也就越多,性能也就越差。

留神:冗余字段的值在一个表中批改了,就要想方法在其余表中更新,否则就会导致数据不统一的问题。

MySQL 数据库 cpu 飙升到 500% 的话他怎么解决?

当 cpu 飙升到 500% 时,先用操作系统命令 top 命令察看是不是 mysqld 占用导致的,如果不是,找出占用高的过程,并进行相干解决。

如果是 mysqld 造成的,show processlist,看看外面跑的 session 状况,是不是有耗费资源的 sql 在运行。找出耗费高的 sql,看看执行打算是否精确,index 是否缺失,或者切实是数据量太大造成。

一般来说,必定要 kill 掉这些线程 (同时察看 cpu 使用率是否降落),等进行相应的调整(比如说加索引、改 sql、改内存参数) 之后,再从新跑这些 SQL。

也有可能是每个 sql 耗费资源并不多,然而忽然之间,有大量的 session 连进来导致 cpu 飙升,这种状况就须要跟利用一起来剖析为何连接数会激增,再做出相应的调整,比如说限度连接数等

大表怎么优化?某个表有近千万数据,CRUD 比较慢,如何优化?分库分表了是怎么做的?分表分库了有什么问题?有用到中间件么?他们的原理晓得么?

当 MySQL 单表记录数过大时,数据库的 CRUD 性能会显著降落,一些常见的优化措施如下:

  • 限定数据的范畴:务必禁止不带任何限度数据范畴条件的查问语句。比方:咱们当用户在查问订单历史的时候,咱们能够管制在一个月的范畴内。;
  • 读 / 写拆散:经典的数据库拆分计划,主库负责写,从库负责读;
  • 缓存:应用 MySQL 的缓存,另外对重量级、更新少的数据能够思考应用利用级别的缓存;
    还有就是通过分库分表的形式进行优化,次要有垂直分表和程度分表

垂直分区

依据数据库外面数据表的相关性进行拆分。例如,用户表中既有用户的登录信息又有用户的根本信息,能够将用户表拆分成两个独自的表,甚至放到独自的库做分库。

简略来说垂直拆分是指数据表列的拆分,把一张列比拟多的表拆分为多张表。如下图所示,这样来说大家应该就更容易了解了。

垂直拆分的长处:能够使得行数据变小,在查问时缩小读取的 Block 数,缩小 I / O 次数。此外,垂直分区能够简化表的构造,易于保护。

垂直拆分的毛病:主键会呈现冗余,须要治理冗余列,并会引起 Join 操作,能够通过在应用层进行 Join 来解决。此外,垂直分区会让事务变得更加简单;

垂直分表

把主键和一些列放在一个表,而后把主键和另外的列放在另一个表中

实用场景

  • 1、如果一个表中某些列罕用,另外一些列不罕用
  • 2、能够使数据行变小,一个数据页能存储更多数据,查问时缩小 I / O 次数
  • 毛病

    • 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法扭转,整个分表逻辑都会扭转,扩展性较差
    • 对于应用层来说,逻辑算法减少开发成本
    • 治理冗余列,查问所有数据须要 join 操作

程度分区

放弃数据表构造不变,通过某种策略存储数据分片。这样每一片数据扩散到不同的表或者库中,达到了分布式的目标。程度拆分能够撑持十分大的数据量。

程度拆分是指数据表行的拆分,表的行数超过 200 万行时,就会变慢,这时能够把一张的表的数据拆成多张表来寄存。举个例子:咱们能够将用户信息表拆分成多个用户信息表,这样就能够防止繁多表数据量过大对性能造成影响。

水品拆分能够反对十分大的数据量。须要留神的一点是: 分表仅仅是解决了繁多表数据过大的问题,但因为表的数据还是在同一台机器上,其实对于晋升 MySQL 并发能力没有什么意义,所以 程度拆分最好分库。

程度拆分可能 反对十分大的数据量存储,利用端革新也少,但 分片事务难以解决,跨界点 Join 性能较差,逻辑简单。

《Java 工程师修炼之道》的作者举荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度,个别的数据表在优化切当的状况下撑持千万以下的数据量是没有太大问题的。如果切实要分片,尽量抉择客户端分片架构,这样能够缩小一次和中间件的网络 I /O。

程度分表

表很大,宰割后能够升高在查问时须要读的数据和索引的页数,同时也升高了索引的层数,进步查问次数

  • 实用场景

    • 1、表中的数据自身就有独立性,例如表中分表记录各个地区的数据或者不同期间的数据,特地是有些数据罕用,有些不罕用。
    • 2、须要把数据寄存在多个介质上。
  • 程度切分的毛病

    • 1、给利用减少复杂度,通常查问时须要多个表名,查问所有数据都需 UNION 操作
    • 2、在许多数据库利用中,这种复杂度会超过它带来的长处,查问时会减少读一个索引层的磁盘次数

上面补充一下数据库分片的两种常见计划:

客户端代理:分片逻辑在利用端,封装在 jar 包中,通过批改或者封装 JDBC 层来实现。当当网的 Sharding-JDBC、阿里的 TDDL 是两种比拟罕用的实现。

中间件代理:在利用和数据两头加了一个代理层。分片逻辑对立保护在中间件服务中。咱们当初谈的 Mycat、360 的 Atlas、网易的 DDB 等等都是这种架构的实现。

分库分表后面临的问题
  • 事务反对 分库分表后,就成了分布式事务了。如果依赖数据库自身的分布式事务管理性能去执行事务,将付出昂扬的性能代价;如果由应用程序去帮助管制,造成程序逻辑上的事务,又会造成编程方面的累赘。
  • 跨库 join
    只有是进行切分,跨节点 Join 的问题是不可避免的。然而良好的设计和切分却能够缩小此类情况的产生。解决这一问题的广泛做法是分两次查问实现。在第一次查问的后果集中找出关联数据的 id, 依据这些 id 发动第二次申请失去关联数据。分库分表计划产品
  • 跨节点的 count,order by,group by 以及聚合函数问题 这些是一类问题,因为它们都须要基于全副数据汇合进行计算。少数的代理都不会主动解决合并工作。解决方案:与解决跨节点 join 问题的相似,别离在各个节点上失去后果后在应用程序端进行合并。和 join 不同的是每个结点的查问能够并行执行,因而很多时候它的速度要比繁多大表快很多。但如果后果集很大,对应用程序内存的耗费是一个问题。
  • 数据迁徙,容量布局,扩容等问题 来自淘宝综合业务平台团队,它利用对 2 的倍数取余具备向前兼容的个性(如对 4 取余得 1 的数对 2 取余也是 1)来调配数据,防止了行级别的数据迁徙,然而仍然须要进行表级别的迁徙,同时对扩容规模和分表数量都有限度。总得来说,这些计划都不是非常的现实,多多少少都存在一些毛病,这也从一个侧面反映出了 Sharding 扩容的难度。
  • ID 问题
  • 一旦数据库被切分到多个物理结点上,咱们将不能再依赖数据库本身的主键生成机制。一方面,某个分区数据库自生成的 ID 无奈保障在全局上是惟一的;另一方面,应用程序在插入数据之前须要先取得 ID, 以便进行 SQL 路由. 一些常见的主键生成策略

UUID 应用 UUID 作主键是最简略的计划,然而毛病也是非常明显的。因为 UUID 十分的长,除占用大量存储空间外,最次要的问题是在索引上,在建设索引和基于索引进行查问时都存在性能问题。Twitter 的分布式自增 ID 算法 Snowflake 在分布式系统中,须要生成全局 UID 的场合还是比拟多的,twitter 的 snowflake 解决了这种需要,实现也还是很简略的,除去配置信息,外围代码就是毫秒级工夫 41 位 机器 ID 10 位 毫秒内序列 12 位。

跨分片的排序分页

般来讲,分页时须要依照指定字段进行排序。当排序字段就是分片字段的时候,咱们通过分片规定能够比拟容易定位到指定的分片,而当排序字段非分片字段的时候,状况就会变得比较复杂了。为了最终后果的准确性,咱们须要在不同的分片节点中将数据进行排序并返回,并将不同分片返回的后果集进行汇总和再次排序,最初再返回给用户。如下图所示:

MySQL 的复制原理以及流程

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

主从复制的作用
  • 主数据库呈现问题,能够切换到从数据库。
  • 能够进行数据库层面的读写拆散。
  • 能够在从数据库上进行日常备份。
MySQL 主从复制解决的问题
  • 数据分布:随便开始或进行复制,并在不同地理位置散布数据备份
  • 负载平衡:升高单个服务器的压力
  • 高可用和故障切换:帮忙应用程序防止单点失败
  • 降级测试:能够用更高版本的 MySQL 作为从库
MySQL 主从复制工作原理
  • 在主库上把数据更高记录到二进制日志
  • 从库将主库的日志复制到本人的中继日志
  • 从库读取中继日志的事件,将其重放到从库数据中

基本原理流程,3 个线程以及之间的关联

主:binlog 线程——记录下所有扭转了数据库数据的语句,放进 master 上的 binlog 中;

从:io 线程——在应用 start slave 之后,负责从 master 上拉取 binlog 内容,放进本人的 relay log 中;

从:sql 执行线程——执行 relay log 中的语句;

复制过程

Binary log:主数据库的二进制日志

Relay log:从服务器的中继日志

第一步:master 在每个事务更新数据实现之前,将该操作记录串行地写入到 binlog 文件中。

第二步:salve 开启一个 I /O Thread,该线程在 master 关上一个一般连贯,次要工作是 binlog dump process。如果读取的进度曾经跟上了 master,就进入睡眠状态并期待 master 产生新的事件。I/ O 线程最终的目标是将这些事件写入到中继日志中。

第三步:SQL Thread 会读取中继日志,并程序执行该日志中的 SQL 事件,从而与主数据库中的数据保持一致。

读写拆散有哪些解决方案?

读写拆散是依赖于主从复制,而主从复制又是为读写拆散服务的。因为主从复制要求 slave 不能写只能读(如果对 slave 执行写操作,那么 show slave status 将会出现 Slave_SQL_Running=NO,此时你须要依照后面提到的手动同步一下 slave)。

计划一: 应用 mysql-proxy 代理

长处:间接实现读写拆散和负载平衡,不必批改代码,master 和 slave 用一样的帐号,mysql 官网不倡议理论生产中应用

毛病:升高性能,不反对事务

计划二: 应用 AbstractRoutingDataSource+aop+annotation 在 dao 层决定数据源。

如果采纳了 mybatis,能够将读写拆散放在 ORM 层,比方 mybatis 能够通过 mybatis plugin 拦挡 sql 语句,所有的 insert/update/delete 都拜访 master 库,所有的 select 都拜访 salve 库,这样对于 dao 层都是通明。plugin 实现时能够通过注解或者剖析语句是读写办法来选定主从库。不过这样仍然有一个问题,也就是不反对事务,所以咱们还须要重写一下 DataSourceTransactionManager,将 read-only 的事务扔进读库,其余的有读有写的扔进写库。

计划三: 应用 AbstractRoutingDataSource+aop+annotation 在 service 层决定数据源,能够反对事务.

毛病:类外部办法通过 this.xx()形式互相调用时,aop 不会进行拦挡,需进行非凡解决。

备份打算,mysqldump 以及 xtranbackup 的实现原理

(1)备份打算

视库的大小来定,一般来说 100G 内的库,能够思考应用 mysqldump 来做,因为 mysqldump 更加笨重灵便,备份工夫选在业务低峰期,能够每天进行都进行全量备份(mysqldump 备份进去的文件比拟小,压缩之后更小)。

100G 以上的库,能够思考用 xtranbackup 来做,备份速度显著要比 mysqldump 要快。个别是抉择一周一个全备,其余每天进行增量备份,备份工夫为业务低峰期。

(2)备份复原工夫

物理备份复原快,逻辑备份复原慢

这里跟机器,尤其是硬盘的速率有关系,以下列举几个仅供参考

20G 的 2 分钟(mysqldump)

80G 的 30 分钟(mysqldump)

111G 的 30 分钟(mysqldump)

288G 的 3 小时(xtra)

3T 的 4 小时(xtra)

逻辑导入工夫个别是备份工夫的 5 倍以上

(3)备份复原失败如何解决

首先在复原之前就应该做足筹备工作,防止复原的时候出错。比如说备份之后的有效性查看、权限查看、空间查看等。如果万一报错,再依据报错的提醒来进行相应的调整。

(4)mysqldump 和 xtrabackup 实现原理
  • mysqldump

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:

xtrabackup 属于物理备份,间接拷贝表空间文件,同时一直扫描产生的 redo 日志并保留下来。最初实现 innodb 的备份后,会做一个 flush engine logs 的操作(老版本在有 bug,在 5.6 上不做此操作会丢数据),确保所有的 redo log 都曾经落盘(波及到事务的两阶段提交

概念,因为 xtrabackup 并不拷贝 binlog,所以必须保障所有的 redo log 都落盘,否则可能会丢最初一组提交事务的数据)。这个工夫点就是 innodb 实现备份的工夫点,数据文件尽管不是一致性的,然而有这段时间的 redo 就能够让数据文件达到一致性(复原的时候做的事

情)。而后还须要 flush tables with read lock,把 myisam 等其余引擎的表给备份进去,备份完后解锁。这样就做到了完满的热备。

数据表损坏的修复形式有哪些?

应用 myisamchk 来修复,具体步骤:

  • 1)修复前将 mysql 服务进行。
  • 2)关上命令行形式,而后进入到 mysql 的 /bin 目录。
  • 3)执行 myisamchk –recover 数据库所在门路 /*.MYI

应用 repair table 或者 OPTIMIZE table 命令来修复,REPAIR TABLE table_name 修复表 OPTIMIZE TABLE table_name 优化表 REPAIR TABLE 用于修复被毁坏的表。OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立刻被回收,应用了 OPTIMIZE TABLE 命令后这些空间将被回收,并且对磁盘上的数据行进行重排(留神:是磁盘上,而非数据库)

作者:ThinkWon,遵循 CC 4.0 BY-SA 版权协定
链接:https://blog.csdn.net/ThinkWo…

正文完
 0