2021数据库考试题及答案 mysql题目和详细答案

1.非聚簇索引一定会回表查询吗?不一定,这涉及到查询语句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再进行回表查询 。
举个简单的例子:假设我们在员工表的年龄上建立了索引,那么当进行的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询.
selectagefromemployeewhereage <202.Mysql删除表几种方式?有什么区别?

  1. delete : 仅删除表数据,支持where条件过滤,支持回滚 。记录日志 。因此比较慢 。delete from links;
  2. truncate: 仅删除所有数据,不支持where条件过滤,不支持回滚 。不记录日志,效率高于delete 。truncate table links;
  3. drop:删除表数据同时删除表结构 。将表所占的空间都释放掉 。删除效率最高 。drop table links;
3.MySQL自增id不连续问题?
  1. 唯一键冲突 假设执行 SQL 的时候 user 表 id = 10,此时在内存中的自增 id 为11,此时发生唯一键冲突写库失败,则 user 表没有 id = 10 这条记录,之后 id 从11开始写入,因此 id 是不连续的 。
  2. 事务回滚 假设同时需要对 user、staff 表进行写库操作,执行 SQL 的时候 user 表 id = 10,此时在内存中的自增 id 为11;staff 表 id = 20,此时内存中的自增 id 为21,一旦事务执行失败,事务回滚,写库失败,则 user 表没有 id = 10 这条记录,staff 表没有 id = 20 这条记录,user 表从11开始写入,staff 表从21开始写入,如此产生 id 不连续的现象 。
  3. 批量写库操作 对于批量插入数据的语句,MySQL 有一个批量申请自增 id 的策略: 1. 语句执行过程中,第一次申请自增 id,会分配 1 个;2. 1 个用完以后,这个语句第二次申请自增 id,会分配 2 个; 3. 2 个用完以后,还是这个语句,第三次申请自增 id,会分配 4 个; 依此类推,同一个语句去申请自增 id,每次申请到的自增 id 个数都是上一次的两倍 。假设批量往 user 表中写入四条记录,则这四条记录将分为三次申请id,第一次分配到 id = 1,第二次分配到 id = 2、3,第三次分配到 id = 4、5、6、7,当批量写入四条记录之后,id = 1、2、3、4将会入库,但是 id = 5、6、7就被废弃了,下一个 id 从8开始 。
4.选择合适的存储引擎?在选择存储引擎时,应根据应用特点选择合适的存储引擎,对于复杂的应用系统可以根据实际情况选择多种存储引擎进行组合 。
下面是常用存储引擎的适用环境 。
  1. MyISAM:5.1及之前版本默认存储引擎 。如果应用是以读操作和插入操作为主,=只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存 储引擎是非常适合的 。MyISAM 是在 Web、数据仓储和其他应用环境下最常使用的存储引擎 之一 。
  2. InnoDB:5.5及之后默认存储引擎 。用于事务处理应用程序,支持外键 。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询以外,还包括很多的更新、 删除操作,那么 InnoDB 存储引擎应该是比较合适的选择 。InnoDB 存储引擎除了有效地降低 由于删除和更新导致的锁定,还可以确保事务的完整提交(Commit)和回滚(Rollback),对于类似计费系统或者财务系统等对数据准确性要求比较高的系统,InnoDB 都是合适的选 择 。
  3. MEMORY:将所有数据保存在 RAM 中,在需要快速定位记录和其他类似数据的环境 下,可提供极快的访问 。MEMORY 的缺陷是对表的大小有限制,太大的表无法 CACHE 在内存中,其次是要确保表的数据可以恢复,数据库异常终止后表中的数据是可以恢复的 。MEMORY 表通常用于更新不太频繁的小表,用以快速得到访问结果 。
  4. MERGE:用于将一系列等同的 MyISAM 表以逻辑方式组合在一起,并作为一个对象引用它们 。MERGE 表的优点在于可以突破对单个 MyISAM 表大小的限制,并且通过将不同 的表分布在多个磁盘上,可以有效地改善MERGE表的访问效率 。这对于诸如数据仓储等VLDB 环境十分适合 。
5.选择合适的数据类型?前提: 使用适合存储引擎 。
选择原则,根据选定的存储引擎,确定如何选择合适的数据类型,下面的选择方法按存储引擎分类 :
  1. MyISAM 数据存储引擎和数据列
MyISAM数据表,最好使用固定长度的数据列代替可变长度的数据列 。
  1. MEMORY存储引擎和数据列MEMORY数据表目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系 。两者都是作为CHAR类型处理的 。
  2. InnoDB 存储引擎和数据列建议使用 VARCHAR类型对于InnoDB数据表,内部的行存储格式没有区分固定长度和可变长度列(所有数据行 都使用指向数据列值的头指针),因此在本质上,使用固定长度的CHAR列不一定比使 用可变长度VARCHAR列简单 。因而,主要的性能因 是数据行使用的存储总量 。由于 CHAR 平均占用的空间多于VARCHAR,因此使用VARCHAR来最小化需要处理的数据行的存储总量和年盘I/O是比较好的 。
6.聊聊Mysql字符集!mysql服务器可以支持多种字符集(可以用show character set命令查看所有mysql支持的字符集),在同一台服务器、同一个数据库、甚至同一个表的不同字段都可以指定使用不同的字符集,相比oracle等其他数据库管理系统,在同一个数据库只能使用相同的字符集,mysql明显存在更大的灵活性 。
mysql的字符集包括字符集(CHARACTER)和校对规则(COLLATION)两个概念 。字符集是用来定义mysql存储字符串的方式,校对规则则是定义了比较字符串的方式 。字符集和校对规则是一对多的关系, MySQL支持30多种字符集的70多种校对规则 。
每个字符集至少对应一个校对规则 。可以用SHOW COLLATION LIKE ‘utf8%’;命令查看相关字符集的校对规则
7.如何选择字符集?对数据库来说,字符集更加重要,因为数据库存储的数据大部分都是各种文字,字符集对数据库的存储,处理性能,以及日后系统的移植,推广都会有影响 。mysql5.6目前支持几十种字符集,包括ucs2,utf16,utf16le,utf32,utf8和utf8mb4等Unicode字符集 。根据应用的需求,考虑以下几方面的因素 。
  1. 满足应用支持语言的需求,如果应用要处理各种各样的文字,或者将发布到使用不同语言的国家或地区,就应该选择Unicode字符集 。对Mysql来说,目前就是utf8,如果要存储emoji表情需使用utf8mb4 。
  2. 如果应用中涉及已有数据的导入,就要充分考虑数据库字符集对已有数据的兼容性 。假如已有数据是gbk文字,如果选择gb2312-80为数据库字符集,就很有可能出现某些文字无法正确导入的问题
  3. 如果数据库只支持一般中文,数据量很大,性能要求也很高,那就应该选择双字节长编码的中文字符集,比如gbk 。因为,相对于utf8而言,gbk比较“小”,每个汉字只占2个字节,而utf8汉字编码需要3个字节,这样可以减少磁盘I/O,数据库Cache以及网络传输的时间,从而提高性能 。相反,如果应用主要处理英文字符,仅有少量汉字数据,那么选择utf8更好,因为gbk,ucs2,utf16的西文字符编码都是2个字节,会造成很多不必要的开销 。
  4. 如果数据库需要做大量的字符运算,如比较,排序等,那么选择定长字符集可能更好,因为定长字符集的处理速度要比变长字符集的处理速度快 。
  5. 如果所有客户端程序都支持相同的字符集,则应该优先选择该字符集作为数据库字符集,这样可以避免因字符集转换带来的性能开销和数据损失 。
建议在能够完全满足应用的前提下,尽量使用小的字为集 。因为更小的字为集意味着能够节省空间然 减少网络传输字节数,同时由于存储空间的较小间接的提高了系统的性能 。
8.如何查询最后一行记录?select*fromlinksorderbyiddesclimit1;9.sql注入问题?SQL注入攻击(SQL Injection),简称为注入攻击,SQL注入,被广泛用于非法获取网站控制权 。这是在应用程序的数据库层中发生的安全漏洞 。在设计程序中,忽略了对输入字符串中包含的SQL命令的检查,并且将数据库误认为是要运行的常规SQL命令,这导致数据库受到攻击,从而可能导致盗窃,修改和删除数据,并进一步导致网站嵌入恶意代码,植入后门程序的危害等 。
注射位置包括
  1. 表单提交,主要是POST请求,还有GET请求 。
  2. URL参数提交,主要是GET请求参数 。
  3. Cookie参数的提交 。
  4. HTTP请求标头中的一些可修改值,例如Referer,User_Agent等 。
  5. 一些边缘输入点,例如.mp3文件的某些文件信息 。
sql注入的危害SQL注入的危害不仅体现在数据库级别,而且还可能危及托管数据库的操作系统 。如果将SQL注入用于挂马,还可能用来传播恶意软件等,这些危害包括但不局限于:
  1. 数据库信息泄漏:泄漏用户存储在数据库中的私人信息 。作为数据存储中心,各种类型的私人信息通常存储在数据库中 。SQL注入攻击能导致这些隐私信息透明于攻击者 。
  2. 篡改网页:通过操作数据库来篡改特定网页 。
  3. 网站被挂马,传播恶意软件:修改数据库一些字段的值,嵌入网马链接,进行挂马攻击 。
  4. 数据库被恶意操作:数据库服务器受到攻击,数据库系统管理员帐户被篡改 。
  5. 服务器受远程控制,并安装了后门 。经由数据库服务器提供的操作系统支持,让黑客得以修改或控制操作系统 。
  6. 破坏硬盘数据并使整个系统瘫痪 。
如何解决SQL注入解决SQL注入问题的关键是严格检查可能来自用户输入的所有数据,并使用最小特权原则进行数据库配置 。常用的方案有:
  1. 所有查询语句都使用数据库提供的参数化查询接口,并且参数化语句使用参数,而不是将用户输入变量嵌入SQL语句中 。几乎所有当前的数据库系统都提供参数化的SQL语句执行接口 。使用此接口可以有效地防止SQL注入攻击 。String sql=”SELECT * FROM user WHERE username=? AND password=?”; //使用?代替参数,预先设置好sql格式,就算在输入sql关键字也不会被sql识别PreparedStatement pstat=conn.prepareStatement(sql);pstat.setString(1,username); //设置问号的值pstat.setString(2,password);pstat.executeQuery();
  2. 对进入数据库的特殊字符(’”<>&*;等)进行转义处理,或编码转换 。
  3. 确认每个数据的类型 。例如,数字数据必须是数字,并且数据库中的存储字段必须与int类型相对应 。
  4. 应严格规定数据长度,以防在一定程度上正确执行较长的SQL注入语句 。
  5. 网站每个数据层的编码是统一的 。建议使用UTF-8编码 。上下层编码不一致可能会导致某些过滤模型被绕过 。
  6. 严格限制网站用户数据库的操作权限,并向该用户提供只能满足其工作要求的权限,从而最大程度地减少了注入攻击对数据库的危害 。
  7. 阻止网站显示SQL错误消息,例如类型错误,字段不匹配等,以防止攻击者使用这些错误消息进行判断 。
  8. 在网站发布之前,建议使用一些专业的SQL注入检测工具来及时检测和修补这些SQL注入漏洞 。
10.NULL和空串判断?MySQL 中的空值包含 NULL 和空字符串 。当匹配 NULL 值条件时,使用 IS NULL 和 IS NOT NULL,当匹配空字符串时,使用“=”“<>”“!=” 。
本文使用一张名为 t_goods 的数据表,该表用来记录商品信息,它的记录如下:
+----+---------------+-----------------+-------------+---------+---------+---------------------+| id | t_category_id | t_category| t_name| t_price | t_stock | t_upper_time|+----+---------------+-----------------+-------------+---------+---------+---------------------+| 1|1| 女装/女士精品| T恤| 39.90| 1000|2020-11-1000:00:00 || 2|1| 女装/女士精品| 连衣裙| 79.90| 2500|2020-11-1000:00:00 || 3|1| 女装/女士精品| 卫衣| 79.90| 1500|2020-11-1000:00:00 || 4|1| 女装/女士精品| 牛仔裤| 89.90| 3500|2020-11-1000:00:00 || 5|1| 女装/女士精品| 百褶裙| 29.90|500|2020-11-1000:00:00 || 6|1| 女装/女士精品| 呢绒外套| 399.90| 1200|2020-11-1000:00:00 || 7|2| 户外运动| 自行车| 399.90| 1000|2020-11-1000:00:00 || 8|2| 户外运动| 山地自行车 |1399.90| 2500|2020-11-1000:00:00 || 9|2| 户外运动| 登山杖| 59.90| 1500|2020-11-1000:00:00 ||10|2| 户外运动| 骑行装备| 399.90| 3500|2020-11-1000:00:00 ||11|2| 户外运动| 户外运动外套| 799.90|500|2020-11-1000:00:00 ||12|2| 户外运动| 滑板| 499.90| 1200|2020-11-1000:00:00 |+----+---------------+-----------------+-------------+---------+---------+---------------------+向 t_goods 数据表中插入两条名称为空字符串,上架时间为 NULL 的数据记录 。
mysql> INSERT INTO t_goods-> (t_category_id, t_category, t_name, t_price, t_stock, t_upper_time)-> VALUES-> (1, '女装/女士精品', '', 399.90, 1200, NULL),-> (2, '户外运动', '', 499.90, 1200, NULL);Query OK, 2 rows affected (0.01 sec)Records: 2Duplicates: 0Warnings: 0SQL语句执行成功 。
匹配 NULL 值例如,查询 t_goods 数据表中上架时间为 NULL的 数据 。
mysql> SELECT id, t_category, t_name, t_price-> FROM t_goods-> WHERE t_upper_time IS NULL;+----+-----------------+-------------+---------+| id | t_category| t_name| t_price |+----+-----------------+-------------+---------+| 13 | 女装/女士精品||399.90 || 14 | 户外运动||499.90 |+----+-----------------+-------------+---------+2 rows in set (0.00 sec)IS NOT NULL 与 IS NULL 相反,用于查询数据表中某个字段的值不是 NULL 的数据记录 。
例如,查询 t_goods 数据表中上架时间不为 NULL 的数据 。
mysql> SELECT id, t_category, t_name, t_price-> FROM t_goods-> WHERE t_upper_time IS NOT NULL;+----+----------------+-------------+---------+| id | t_category| t_name| t_price |+----+----------------+-------------+---------+|1 | 女装/女士精品| T恤|39.90 ||2 | 女装/女士精品| 连衣裙|79.90 ||3 | 女装/女士精品| 卫衣|79.90 ||4 | 女装/女士精品| 牛仔裤|89.90 ||5 | 女装/女士精品| 百褶裙|29.90 ||6 | 女装/女士精品| 呢绒外套|399.90 ||7 | 户外运动| 自行车|399.90 ||8 | 户外运动| 山地自行车| 1399.90 ||9 | 户外运动| 登山杖|59.90 || 10 | 户外运动| 骑行装备|399.90 || 11 | 户外运动| 户外运动外套 |799.90 || 12 | 户外运动| 滑板|499.90 |+----+----------------+-------------+---------+12 rows in set (0.00 sec)匹配空字符串例如,查询 t_goods 数据表中名称为空字符串的数据 。
mysql> SELECT id, t_category, t_name, t_price-> FROM t_goods-> WHERE t_name = '';+----+-----------------+-------------+---------+| id | t_category| t_name| t_price |+----+-----------------+-------------+---------+| 13 | 女装/女士精品||399.90 || 14 | 户外运动||499.90 |+----+-----------------+-------------+---------+2 rows in set (0.00 sec)使用“<>”或“!=”运算符能够查询数据表中某个字段的值不是空字符串的数据 。例如,查询 t_goods 数据表中名称不是空字符串的数据 。
mysql> SELECT id, t_category, t_name, t_price-> FROM t_goods-> WHERE t_name <> '';+----+----------------+-------------+---------+| id | t_category| t_name| t_price |+----+----------------+-------------+---------+|1 | 女装/女士精品| T恤|39.90 ||2 | 女装/女士精品| 连衣裙|79.90 ||3 | 女装/女士精品| 卫衣|79.90 ||4 | 女装/女士精品| 牛仔裤|89.90 ||5 | 女装/女士精品| 百褶裙|29.90 ||6 | 女装/女士精品| 呢绒外套|399.90 ||7 | 户外运动| 自行车|399.90 ||8 | 户外运动| 山地自行车| 1399.90 ||9 | 户外运动| 登山杖|59.90 || 10 | 户外运动| 骑行装备|399.90 || 11 | 户外运动| 户外运动外套|799.90 || 12 | 户外运动| 滑板|499.90 |+----+----------------+-------------+---------+12 rows in set (0.00 sec)11.InnoDB默认事务隔离级别?如何查看事务隔离级别?
  • 可重复读取(REPEATABLE-READ)
  • 查看事务隔离级别:
12.什么是回表查询?回表就是先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树 。
因此,可以通过索引先查询出id字段,再通过主键id字段,查询行中的字段数据,即通过再次查询提供MySQL查询速度 。
13.如何避免回表?
  1. 尽量使用主键
  2. 如果必须使用辅助索引,那么尽量避免使用*,直接列出所需列名使用索引覆盖 。如果所需数据仅包含辅助索引列,那么它将不读取主键,因为辅助索引包含辅助索引列的值
14.索引覆盖是什么?索引覆盖是一种避免回表查询的优化策略 。具体的做法就是将要查询的数据作为索引列建立普通索引(可以是单列索引,也可以一个索引语句定义所有要查询的列,即联合索引),这样的话就可以直接返回索引中的的数据,不需要再通过聚集索引去定位行记录,避免了回表的情况发生 。
覆盖索引的定义与注意事项
如果一个索引覆盖(包含)了所有需要查询的字段的值,这个索引就是覆盖索引 。因为索引中已经包含了要查询的字段的值,因此查询的时候直接返回索引中的字段值就可以了,不需要再到表中查询,避免了对主键索引的二次查询,也就提高了查询的效率 。
要注意的是,不是所有类型的索引都可以成为覆盖索引的 。因为覆盖索引必须要存储索引的列值,而哈希索引、空间索引和全文索引等都不存储索引列值,索引MySQL只能使用B-Tree索引做覆盖索引 。
另外,当发起一个被索引覆盖的查询(索引覆盖查询)时,在explain(执行计划)的Extra列可以看到【Using Index】的信息 。
覆盖索引的优点
1.索引条目通常远小于数据行的大小,因为覆盖索引只需要读取索引,极大地减少了数据的访问量 。
2.索引是按照列值顺序存储的,对于IO密集的范围查找会比随机从磁盘读取每一行数据的IO小很多 。
3.一些存储引擎比如MyISAM在内存中只缓存索引,数据则依赖操作系统来缓存,因此要访问数据的话需要一次系统调用,使用覆盖索引则避免了这一点 。
4.由于InnoDB的聚簇索引,覆盖索引对InnoDB引擎下的数据库表特别有用 。因为InnoDB的二级索引在叶子节点中保存了行的主键值,如果二级索引能够覆盖查询,就避免了对主键索引的二次查询 。
15.视图的优缺点?优点1.简化了操作:此时我们完全不用关心视图是怎么处理数据的,我们只需要知道如何使用这个结果集即可,视图相当于一个中间层 。
2.更加安全:比如我们可以让用户有权去访问某个视图,但是不能访问原表,这样就可以起到保护原表中某些数据的作用 。
3.管理权限是无法细致到某一个列的,通过视图,则很容易实现 。
4.降低耦合:假如我们以后要修改原表的结构,那么我们可以通过修改视图的定义即可,而不用修改应用程序,对访问者是不会造成影响的,一般来说,这样代价会更小 。
缺点1.性能:从数据库视图查询数据可能会很慢,特别是如果视图是基于其他视图创建的 。
2.表依赖关系:将根据数据库的基础表创建一个视图 。每当更改与其相关联的表的结构时,都必须更改视图 。
16.主键和唯一索引区别?主键是一种约束,唯一索引是一种索引,两者在本质上是不同的 。
  1. 主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键 。
  2. 唯一性索引列允许空值,而主键列不允许为空值 。
  3. 主键列在创建时,已经默认为非空值 + 唯一索引了 。
  4. 主键可以被其他表引用为外键,而唯一索引不能 。
  5. 一个表最多只能创建一个主键,但可以创建多个唯一索引 。
  6. 主键和唯一索引都可以有多列 。
  7. 主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等 。
  8. 在 RBO 模式下,主键的执行计划优先级要高于唯一索引 。两者可以提高查询的速度 。
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针 。
总体来说:主键相当于一本书的页码,索引相当于书的目录 。
其实主键和索引都是键,不过主键是逻辑键,索引是物理键,意思就是主键不实际存在,而索引实际存在在数据库中,主键一般都要建,主要是用来避免一张表中有相同的记录,索引一般可以不建,但如果需要对该表进行查询操作,则最好建,这样可以加快检索的速度 。
17.如何随机获取一条记录?select * from posts ORDER BY rand() LIMIT 1;18.查看当前表有哪些索引?show index from posts;19.什么情况下索引不生效?
  1. 使用不等于查询
  2. NULL值
  3. 列参与了数学运算或者函数 。
  4. 在字符串like时左边是通配为.比如 %xxx 。
  5. 当mysql分析全表扫描比使用索引快的时候不使用索引 。
  6. 当使用联合索引,前面一个条件为范围查询,后面的即使符合最左前缀原则,也无法使用 引.
20.聊聊MVVC?本质多版本并发控制(Multiversion concurrency control,MCC 或 MVCC),是数据库管理系统常用的一种并发控制,也用于程序设计语言实现事务内存 。乐观并发控制和悲观并发控制都是通过延迟或者终止相应的事务来解决事务之间的竞争条件来保证事务的可串行化;这两种并发控制机制确实能够从根本上解决并发事务的可串行化的问题,但是其实都是在解决写冲突的问题,两者区别在于对写冲突的乐观程度不同(悲观锁也能解决读写冲突问题,但是性能就一般了) 。而在实际使用过程中,数据库读请求是写请求的很多倍,我们如果能解决读写并发的问题的话,就能更大地提高数据库的读性能,而这就是多版本并发控制所能做到的事情 。
与悲观并发控制和乐观并发控制不同的是,MVCC是为了解决读写锁造成的多个、长时间的读操作饿死写操作问题,也就是解决读写冲突的问题 。MVCC 可以与前两者中的任意一种机制结合使用,以提高数据库的读性能 。
数据库的悲观锁基于提升并发性能的考虑,一般都同时实现了多版本并发控制 。不仅是MySQL,包括Oracle、PostgreSQL等其他数据库系统也都实现了MVCC,但各自的实现机制不尽相同,因为MVCC没有一个统一的实现标准 。
总的来说,MVCC的出现就是数据库不满用悲观锁去解决读-写冲突问题,因性能不高而提出的解决方案 。
实现方式MVCC的实现,是通过保存数据在某个时间点的快照来实现的 。每个事务读到的数据项都是一个历史快照,被称为快照读,不同于当前读的是快照读读到的数据可能不是最新的,但是快照隔离能使得在整个事务看到的数据都是它启动时的数据状态 。而写操作不覆盖已有数据项,而是创建一个新的版本,直至所在事务提交时才变为可见 。
当前读和快照读什么是MySQL InnoDB下的当前读和快照读?
  • 当前读像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁 。
  • 快照读像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是未提交读和串行化级别,因为未提交读总是读取最新的数据行,而不是符合当前事务版本的数据行 。而串行化则会对所有读取的行都加锁 。
优缺点MVCC 使大多数读操作都可以不用加锁,这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行 。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作 。
适用场景
  1. 解决读-写冲突的无锁并发控制 。
  2. 与上面两者结合,提升它们的读性能 。
  3. 可以解决脏读,幻读,不可重复读等事务问题,更新丢失问题除外 。
21.sql语句的执行流程!
  1. client和server建立连接,client发送sql至server(对应连接器这一过程)
  2. server如果在查询缓存中发现了该sql,则直接使用查询缓存的结果返回给client,如果查询缓存中没有,则进入下面的步骤(对应查询缓存这一过程,8.0这一过程已经不存在了,8.0完全抛弃了这个功能)
  3. server对sql进行语法分析,识别出sql里面的字符串是否符合标准,比如select关键字不能写错(对应分析器这一过程)
  4. server对sql进行语义分析,识别出sql里面的字符串的具体意思是什么,比如T1是表名,C1是列名(对应分析器这一过程 。3、4步其实解析的过程,这个解析的过程是分析器的工作不是优化器的工作)
  5. server确定sql的执行路径,比如走索引还是全表,多表连接时哪张表先走哪张表后走,当你的where条件的可读性和效率有冲突时mysql内部还会自动进行优化,也就是大家理解的重写where子句(对应优化器这一过程)
  6. server对执行sql的用户进行权限检查,比如对表是否有权限执行(对应执行器这一过程)
  7. server执行该sql语句,发送结果给client(对应执行器这一过程)
连接器–>查询缓存–>分析器–>优化器–>执行器
如果表 T1 中没有字段 C1,而执行select * from T1 where C1=1会报错不存在C1这个列,这个过程对应上面第4个过程,对应分析器这一过程
如果用户对T1表没有权限,而执行select * from T1 where C1=1会报错对表T1没有权限,这个过程对应上面第6个过程,对应执行器这一过程
22.聊聊select 语句执行计划!我们都知道用explain xxx分析sql语句的性能,但是具体从explain的结果怎么分析性能以及每个字段的含义你清楚吗?这里我做下总结记录,也是供自己以后参考 。
首先需要注意:MYSQL 5.6.3以前只能EXPLAIN SELECT; MYSQL5.6.3以后就可以EXPLAIN SELECT,UPDATE,DELETE
explain结果示例:
mysql> explain select * from staff;+----+-------------+-------+------+---------------+------+---------+------+------+-------+| id | select_type | table | type | possible_keys | key| key_len | ref| rows | Extra |+----+-------------+-------+------+---------------+------+---------+------+------+-------+|1 | SIMPLE| staff | ALL| NULL| NULL | NULL| NULL |2 | NULL|+----+-------------+-------+------+---------------+------+---------+------+------+-------+1 row in set先上一个官方文档表格的中文版:
Column含义id查询序号select_type查询类型table表名partitions匹配的分区typejoin类型prossible_keys可能会选择的索引key实际选择的索引key_len索引的长度ref与索引作比较的列rows要检索的行数(估算值)filtered查询条件过滤的行数的百分比Extra额外信息
这是explain结果的各个字段,分别解释下含义:
1. idSQL查询中的序列号 。
id列数字越大越先执行,如果说数字一样大,那么就从上往下依次执行 。
2. select_type查询的类型,可以是下表的任何一种类型:
select_type类型说明SIMPLE简单SELECT(不使用UNION或子查询)PRIMARY最外层的SELECTUNIONUNION中第二个或之后的SELECT语句DEPENDENT UNIONUNION中第二个或之后的SELECT语句取决于外面的查询UNION RESULTUNION的结果SUBQUERY子查询中的第一个SELECTDEPENDENT SUBQUERY子查询中的第一个SELECT, 取决于外面的查询DERIVED衍生表(FROM子句中的子查询)MATERIALIZED物化子查询UNCACHEABLE SUBQUERY结果集无法缓存的子查询,必须重新评估外部查询的每一行UNCACHEABLE UNIONUNION中第二个或之后的SELECT,属于无法缓存的子查询
DEPENDENT 意味着使用了关联子查询 。
3. table查询的表名 。不一定是实际存在的表名 。可以为如下的值:
  • <unionM,N>: 引用id为M和N UNION后的结果 。
  • <derivedN>: 引用id为N的结果派生出的表 。派生表可以是一个结果集,例如派生自FROM中子查询的结果 。
  • <subqueryN>: 引用id为N的子查询结果物化得到的表 。即生成一个临时表保存子查询的结果 。
4. type(重要)这是最重要的字段之一,显示查询使用了何种类型 。从最好到最差的连接类型依次为:
system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL
除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一个索引 。
  • 1、system
表中只有一行数据或者是空表,这是const类型的一个特例 。且只能用于myisam和memory表 。如果是Innodb引擎表,type列在这个情况通常都是all或者index
  • 2、const
最多只有一行记录匹配 。当联合主键或唯一索引的所有字段跟常量值比较时,join类型为const 。其他数据库也叫做唯一索引扫描
  • 3、eq_ref
多表join时,对于来自前面表的每一行,在当前表中只能找到一行 。这可能是除了system和const之外最好的类型 。当主键或唯一非NULL索引的所有字段都被用作join联接时会使用此类型 。
eq_ref可用于使用’=’操作符作比较的索引列 。比较的值可以是常量,也可以是使用在此表之前读取的表的列的表达式 。
相对于下面的ref区别就是它使用的唯一索引,即主键或唯一索引,而ref使用的是非唯一索引或者普通索引 。eq_ref只能找到一行,而ref能找到多行 。
  • 4、ref
对于来自前面表的每一行,在此表的索引中可以匹配到多行 。若联接只用到索引的最左前缀或索引不是主键或唯一索引时,使用ref类型(也就是说,此联接能够匹配多行记录) 。
ref可用于使用’=’或'<=>’操作符作比较的索引列 。
  • 5、 fulltext
使用全文索引的时候是这个类型 。要注意,全文索引的优先级很高,若全文索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引
  • 6、ref_or_null
跟ref类型类似,只是增加了null值的比较 。实际用的不多 。
eg.SELECT * FROM ref_tableWHERE key_column=expr OR key_column IS NULL;
  • 7、index_merge
表示查询使用了两个以上的索引,最后取交集或者并集,常见and,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取多个索引,性能可能大部分时间都不如range
  • 8、unique_subquery
用于where中的in形式子查询,子查询返回不重复值唯一值,可以完全替换子查询,效率更高 。该类型替换了下面形式的IN子查询的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr)
  • 9、index_subquery
该联接类型类似于unique_subquery 。适用于非唯一索引,可以返回重复值 。
  • 10、range
索引范围查询,常见于使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等运算符的查询中 。
SELECT * FROM tbl_nameWHERE key_column BETWEEN 10 and 20;SELECT * FROM tbl_nameWHERE key_column IN (10,20,30);
  • 11、index
索引全表扫描,把索引从头到尾扫一遍 。这里包含两种情况: 一种是查询使用了覆盖索引,那么它只需要扫描索引就可以获得数据,这个效率要比全表扫描要快,因为索引通常比数据表小,而且还能避免二次查询 。在extra中显示Using index,反之,如果在索引上进行全表扫描,没有Using index的提示 。
# 此表见有一个name列索引 。# 因为查询的列name上建有索引,所以如果这样type走的是indexmysql> explain select name from testa;+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+| id | select_type | table | type| possible_keys | key| key_len | ref| rows | Extra|+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+|1 | SIMPLE| testa | index | NULL| idx_name | 33| NULL |2 | Using index |+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+1 row in set# 因为查询的列cusno没有建索引,或者查询的列包含没有索引的列,这样查询就会走ALL扫描,如下:mysql> explain select cusno from testa;+----+-------------+-------+------+---------------+------+---------+------+------+-------+| id | select_type | table | type | possible_keys | key| key_len | ref| rows | Extra |+----+-------------+-------+------+---------------+------+---------+------+------+-------+|1 | SIMPLE| testa | ALL| NULL| NULL | NULL| NULL |2 | NULL|+----+-------------+-------+------+---------------+------+---------+------+------+-------+1 row in set# 包含有未见索引的列mysql> explain select * from testa;+----+-------------+-------+------+---------------+------+---------+------+------+-------+| id | select_type | table | type | possible_keys | key| key_len | ref| rows | Extra |+----+-------------+-------+------+---------------+------+---------+------+------+-------+|1 | SIMPLE| testa | ALL| NULL| NULL | NULL| NULL |2 | NULL|+----+-------------+-------+------+---------------+------+---------+------+------+-------+1 row in set
  • 12、all
全表扫描,性能最差 。
5. partitions版本5.7以前,该项是explain partitions显示的选项,5.7以后成为了默认选项 。该列显示的为分区表命中的分区情况 。非分区表该字段为空(null) 。
6. possible_keys查询可能使用到的索引都会在这里列出来
7. key查询真正使用到的索引 。select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个 。
8. key_len查询用到的索引长度(字节数) 。如果是单列索引,那就整个索引长度算进去,如果是多列索引,那么查询不一定都能使用到所有的列,用多少算多少 。留意下这个列的值,算一下你的多列索引总长度就知道有没有使用到所有的列了 。
key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中 。
9. ref如果是使用的常数等值查询,这里会显示const,如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段,如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func
10. rows(重要)rows 也是一个重要的字段 。这是mysql估算的需要扫描的行数(不是精确值) 。这个值非常直观显示 SQL 的效率好坏, 原则上 rows 越少越好.
11. filtered这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数 。这个字段不重要
12. extra(重要)EXplain 中的很多额外的信息会在 Extra 字段显示, 常见的有以下几种内容:
  • distinct:在select部分使用了distinc关键字
  • Using filesort:当 Extra 中有 Using filesort 时, 表示 MySQL 需额外的排序操作, 不能通过索引顺序达到排序效果. 一般有 Using filesort, 都建议优化去掉, 因为这样的查询 CPU 资源消耗大.
# 例如下面的例子:mysql> EXPLAIN SELECT * FROM order_info ORDER BY product_name G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: order_infopartitions: NULLtype: indexpossible_keys: NULLkey: user_product_detail_indexkey_len: 253ref: NULLrows: 9filtered: 100.00Extra: Using index; Using filesort1 row in set, 1 warning (0.00 sec)我们的索引是KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)但是上面的查询中根据 product_name 来排序, 因此不能使用索引进行优化, 进而会产生 Using filesort.如果我们将排序依据改为 ORDER BY user_id, product_name, 那么就不会出现 Using filesort 了. 例如:mysql> EXPLAIN SELECT * FROM order_info ORDER BY user_id, product_name G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: order_infopartitions: NULLtype: indexpossible_keys: NULLkey: user_product_detail_indexkey_len: 253ref: NULLrows: 9filtered: 100.00Extra: Using index1 row in set, 1 warning (0.00 sec)
  • Using index“覆盖索引扫描”, 表示查询在索引树中就可查找所需数据, 不用扫描表数据文件, 往往说明性能不错
  • Using temporary查询有使用临时表, 一般出现于排序, 分组和多表 join 的情况, 查询效率不高, 建议优化.
23.表最多可创建多少列,多少索引?前言: 网上关于一张mysql表最多可以创建多少个索引?基本就是两种答案,一种是不限制,一种是16列, 我认为16的由来应该网上传着传着给扭曲, 因为mysql的单个索引最多能包括16列,但是这个是一个索引包含几列的答案而不是一张可以建多少个索引.真的是误导人啊!因为mysql的一些限制跟具体存储引擎有关,为此以下只列出我们最常用的innoDB和myisam,其他存储引擎的具体限制可以去官网找.
  • innoDB: 最多创建1017列, 最多64个二级索引, 单个索引最多包含16列, 索引最大长度767字节(其实行格式为REDUNDANT,COMPACT最高为767字节,但行格式为DYNAMIC,COMPRESSED最高可达为3072字节), 行大小最大65536字节
  • mysiam: 最多4096列, 最多64个二级索引, 单个索引最多包含16列, 索引最大长度1000字节, 行大小最大65536字节
mysql官方文档地址
  • innoDB限制的官方文档: https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html
  • myisam限制的官方文档: https://dev.mysql.com/doc/refman/8.0/en/myisam-storage-engine.html
这个问题要根据Mysql具体版本,具体引擎来回答.
24.为什么最好建立一个主键?主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键.设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全.
25.字段为什么要求建议为not null?MySQL官网这样介绍:
NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte.
null值会占用更多的字节,且会在程序中造成很多与预期不符的情况.
  • 很多表都包含可为NULL(空值)的列,即使应用程序并不需要保存NULL 也是如此,这是因为可为NULL 是列的默认属性 。通常情况下最好指定列为NOT NULL, 除非真的需要存储NULL 值 。
  • 如果查询中包含可为NULL 的列,对MySQL来说更难优化,因为可为NULL 的列 使得索引、 索引统计和值比较都更复杂 。可为 N ULL的列会使用更多的存储空间,在MySQL里也需要特殊处理 。当可为NULL的列被索引时,每个索引记录需要一个额 外的字节,在MyISAM 里甚至还可能导致固定大小的索引(例如只有一个整数列的索引)变成可变大小的索引 。
  • 通常把可为NULL 的列改为NOT NULL 带来的性能提升比较小,所以(调优时)没有 必要首先在现有schema中查找井修改掉这种情况,除非确定这会导致问题 。但是,如果计划在列上建索引,就应该尽扯避免设计成可为 NULL 的列 。
  • 当然也有例外,例如值得一提的是,lnnoDB 使用单独的位 (bit) 存储NULL 值,所以对于稀疏数据 有很好的空间效率 。但这一点不适用千MyISAM 。
26.varchar(10)和int(10)代表什么含义varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.也就是说,int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示 。
27.视图是什么?对比普通表优势?视图(View)是一种虚拟存在的表,对于使用视图的用户来说基本上是透明的 。视图并 不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时 动态生成的 。
视图相对于普通的表的优势主要包括以下几项 。
  • 简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集 。
  • 安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能 限制到某个行某个列,但是通过视图就可以简单的实现 。
  • 数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加 列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问 者的影响 。
28.coun()在不同引擎的实现方式?count(

    推荐阅读