# MySQL 的存储引擎
`MyISAM`(默认表类型): 非事务的存储引擎, 基于传统的 `ISAM`(有索引的顺序访问方法) 类型, 是存储记录和文件的标准方法, 不是事务安全, 不支持外键, 适用于频繁的查询. 表锁, 不会出现死锁, 适合小数据和小并发.
- 为什么不会出死锁?(没有事务就不会继续持有锁)
答: 因为 `MyISAM` 再查询的时候, 会同时锁定这个 `sql` 里面所有用到的表 (获取锁的顺序是一致的), 不局限与一张表, 再写锁又重叠时, 就得等待.
** 注意:[`MySQL5.5` 之前默认的是 `MyISAM` 引擎了, 5.5 之后的版本默认都是 `innodb` 作为存储引擎] **
`innodb`: 支持事务安全的存储引擎, 适用于插入和更新, 支持外键, 行锁, 事务. 适合大数据, 大并发. 特别是针对多个并发和 `QPS` 较高的情况.
- `QPS:` 就是每秒查询率,`QPS` 是对一个特定服务器再规定时间内能处理多少流量的衡量标准.
- `TPS:` 就是每秒传输处理的事务个数.
- `innodb` 的行锁模式: 共享锁, 排他锁, 意向共享锁 (表锁), 意向排他锁 (表锁), 间隙锁.(注意: 如果 `sql` 语句没有使用索引,`innodb` 不能确定操作的行时, 使用意向锁 (表锁)).
- 死锁问题
- 什么是死锁?
死锁就是当俩个事务都需要获取对方持有的排他锁才能完成事务的时候, 就导致了循环锁等待, 常见的死锁类型.
- 解决办法
1. 数据库参数
2. 尽量约定程序读取表的顺序
3. 在处理一个表时, 尽量对处理的顺序排序
4. 调整事务隔离级别 (避免俩个事务同时操作一行不存在的数据, 容易发生死锁)
存储引擎还有:
- `MERGE:` 将多个类似的 `MyISAM` 表分组为一个表, 可以处理非事务性表, 默认情况下包括这些表.
- `MEMORY:` 提供内存中的表, 以前称为堆. 它在 RAM 中处理所有数据, 以便比在磁盘上存储数据更快地访问. 用于快速查找引用和其他相同的数据.
- `EXAMPLE:` 可以使用此引擎创建表, 但不能存储或获取数据. 这样做的目的是教开发人员如何编写新的存储引擎.
- `ARCHIVE:` 用于存储大量数据, 不支持索引.
- `CSV:` 在文本文件中以逗号分隔值格式存储数据.
- `BLACKHOLE:` 受要存储的数据, 但始终返回空.
- `FEDERATED:` 将数据存储在远程数据库中.
# 数据表的类型
`MyISAM`,`InnoDB`,`MEMORY`,`HEAP`,`BOB`,`ARCHIVE`,`CSV` 等
- `MYISAM:` 成熟稳定, 易于管理, 快速读取. 表级锁.
- `Innodb:` 数据行锁. 占用空间大, 不支持全文索引.
# `MySQL` 作为发布系统的储存, 一天五万条以上的增量, 怎么优化?
1. 设计良好的数据库结构, 允许部分数据冗余, 尽量避免 join 查询, 提高效率.
2. 选择合适的表字段类型和存储引擎, 适当添加索引.
3. `MySQL` 库主从读写分离.
4. 找规律分表, 减少表单中的数据量, 提高查询速度.
5. 添加缓存机制. 可以使用 `Redis` 缓存.
6. 不经常改动的页面, 生成静态页面.
7. 写高效率的 `sql` 语句. 如:`SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE`.
为什么要避免使用 join 查询?
答: 减少消耗.
# 对于大流量网站, 如何解决各页面统计访问量问题?
1. 确认服务器是否能支撑当前访问量.
2. 优化数据库访问.
3. 禁止外部访问, 如图片盗链.
4. 控制文件下载.
5. 使用不同主机进行分流.
6. 使用浏览统计软件, 了解访问量, 有针对性的进行优化.
# 如何进行 `SQL` 优化?
1. 选择正确的存储引擎.
每个引擎都有利有弊, 比如 `MyISAM`, 适用于大量查询, 对大量写操作并不是很好,`update` 一个字段都会把整个表锁起来, 而 I`nnodb`, 对一些小的应用, 它比 `MyISAM` 慢, 但它支持行锁, 再写操作的时候, 很优秀, 它还支持更多的高级应用.
2. 优化字段的数据类型
一个原则, 越小的越快, 如果一个表只有几列, 那我们就不用用 `INT` 来做主键, 可以使用 `MEDIUMINT`,`SMALLINT` 或是更小的 `TINYINT` 会更经济一些, 如果不需要记录时间, 使用 `DATE` 要比 `DATETIME` 好的多, 也要留够足够的空间进行扩展.
3. 为搜索字段添加索引
索引不一定只添加给主键或唯一的字段, 如果在表中有某个字段经常用来做搜索, 那就为它建立索引, 如果要搜索的字段是大的文本字段, 那应该为它建立全文索引.
4. 避免使用 `select *` 因为从数据库读出的数据越多, 那么查询就会越慢. 如果数据库服务和 web 服务器在不同的机器上的话, 还会增加网络传输的负载. 即使要查询表的所有字段, 也尽量不要用 `*` 通配符.
5. 使用 `ENUM` 而不是 `VARCHAR`
`ENUM` 类型是非常快和紧凑的, 它保存的是 `TINYINT`, 但外表上显示的是字符串, 做一些选项列表很好, 比如: 性别, 民族, 部门, 状态之类的字段, 取值有限而且固定.
6. 尽可能使用 `NOT NULL`
`NULL` 其实也需要额外空间的, 在进行比较的时候, 程序也会变得复杂, 并不是并不可以用 `NULL`, 在现实的复杂情况下, 依然会有些情况需要使用 `NULL` 值.
7. 固定长度的表会更快
如果表中的所有字段都是固定长度的, 那整个表会被认为是 `"static"` 或 "`fixed-lenght"`. 例如表中没有 `VARCHAR`,`TEXT`,`BLOB`, 只要表中其中一个字段是这些类型, 那么这个表就不是 "固定长度静态表" 了, 这样的话 `MySQL` 引擎会用另一种方法来处理.
固定长度的表也容易被缓存和重建, 唯一的副作用就是, 固定长度的字段会浪费一些空间, 因为固定长度的字段无论用不用, 都会分配那么多的空间.
# 如何设计一个高并发的系统
1. 数据库优化, 喝的事务隔离级别,`SQL` 语句, 索引优化.
2. 使用缓存, 尽量减少数据库 `IO` 操作.
3. 分布式数据库, 分布式缓存.
4. 服务器负载均衡.
# 什么情况下设置了索引却无法使用
1. 以 % 开头 `LIKE`, 模糊匹配.
2. `OR` 语句前后没有同时使用索引.
3. 数据类型出现隐式转化, 如 `varchar` 不加单引号可能会转换为 `int` 型.
# `SQL` 注入的主要特点
1. 变种极多, 攻击简单, 危害极大.
2. 未经授权操作数据库的数据.
3. 恶意篡改网页.
4. 网页挂木马.
5. 私自添加系统账号或是数据库使用者账号.
# 优化数据库的方法
1. 选取最适合的字段属性, 尽可能减少定义字段宽度, 尽量把字段设成 `NOT NULL`.
2. 使用 `exists` 替代 `in`, 用 `not exists` 替代 `not in`.
3. 使用连接 `(JOIN)` 来替代子查询.
4. 适用联合 `(NUION)` 来代替手动创建的临时表.
5. 事务处理.
6. 锁定表, 优化事务处理.
7. 适当用外键, 优化锁定表.
8. 建立索引.
9. 优化查询语句.
# 数据库中的事务是什么
事务作为一个单元的一组有序的数据操作, 如果组中的所有操作都完成, 则认定事务成功, 即使只有一个失败, 事务也不成功. 如果所有操作完成, 事务则进行提交, 其修改将作用于所有其他数据库进程. 如果一个操作失败, 则事务将回滚, 该事务所有的操作的影响都会取消.
- `ACID` 四大特性
- 原子性: 不可分割, 事务要么全部被执行, 要么全部不执行.
- 一致性: 事务的执行使得数据库从一种正确的状态转换成另一种正确的状态.
- 隔离性: 在事务正确提交前, 不允许把该事务对数据的任何改变提供给任何其他事务.
- 持久性: 事务正确提交后, 将结果永久保存到数据库中, 即使在事务提交后, 有了其他故障, 事务处理结果也会得到保存.
# 索引的目的是什么?
1. 快速访问数据表中特定信息, 提高检索速度.
2. 创建唯一性索引, 保证每一行数据的唯一性.
3. 加速表和表之间的连接.
4. 使用分组和排序子句进行数据检索时, 可显著的减少分组和排序的时间.
# 索引对数据库系统的负面影响是什么?
创建索引和维护索引需要消耗时间, 这个时间会随着数据量的增加而增加, 索引需要占用物理空间. 当对表进行增删改查的时候索引也需要动态维护, 这样就降低了数据的维护速度.
# 为数据表建立索引的原则
1. 频繁使用的, 用以缩小查询范围的字段上建立索引.
2. 频繁使用的, 需要排序的字段上建立索引.
# 什么情况下不宜建立索引
对于查询中涉及很少的列, 或是重复值较多的列, 不宜建立索引.
一些特殊的数据类型, 不宜就建立索引. 如 `text` 文本字段.
# 左连接和右连接的区别
左连接:
- 左连接会读取左表中的全部数据, 即使右表中没有对应的数据 (如果俩个表有相同的数据, 只会显示一个), 用 `NULL` 填充.
右连接:
- 右连接会读取右表的全部数据, 即使左表中没有对应的数据 (如果俩个表有相同的数据, 只会显示一个), 用 `NULL` 填充.
# 什么是锁?
数据库是一个多用户使用的共享资源, 当多个用户并发的存取数据时, 在数据库中就会产生多个事务同时存取同一个数据的情况, 若对并发操作不加控制可能就会读取和储存不正确的数据, 破坏数据库的一致性.
# 什么是存储过程, 用什么来调用?
存储过程就是一个预编译的 `SQL` 语句, 优点是允许模块化设计, 只需要创建一次, 就可以在该程序中多次调用, 如果某次操作需要执行多次 `SQL`, 使用存储过程比单纯的 `SQL` 语句要快. 可以使用一个命令对象进行调用.
# 索引的作用, 和它的优缺点
索引就是一种特殊的查询表, 数据库引擎可以用它加速对数据的检索, 索引是唯一的, 在创建时可以以指定单个列或是多个列. 缺点是它减慢了数据录入的速度, 同时也增加了数据库的尺寸大小.
# 主键, 外键, 索引的区别?
主键:
- 唯一标识一条记录, 不可重复, 不可为 `NULL`.
- 用来保证数据的完整性.
- 只能有一个.
外键:
- 表的外键是另一个表的主键, 外键可以重复, 可以为空.
- 用来和其他表建立联系.
- 一个表可以有多个外键.
索引:
- 该字段没有重复值, 可以有一个是空值.
- 提高查询效率排序速度.
- 一个表可以有多个唯一索引.
# 对 `SQL` 语句的优化方法
1. 避免在索引列上使用计算.
2. 避免在索引列上使用 `IS NULL` 和 `IS NOT NULL`.
3. 对查询进行优化, 尽量避免全表扫描, 首先因该考虑在 `where` 和 `order by` 涉及的列上建立索引.
4. 避免在 `where` 子句对字段进行 null 值判断, 这件导致引擎放弃使用索引而进行全表扫描.
5. 避免在 `where` 子句中对字段进行表达式操作, 也会导致引擎放弃使用索引而进行全表扫描.
# `SQL` 语句中 "相关子查询" 和 "非相关子查询" 有什么区别
如果你想加载一篇你写过的. md 文件, 在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作.
子查询: 嵌套在其他查询中的查询.
非相关子查询:
- 非相关子查询是独立于外部查询的子查询, 子查询总共执行一次, 执行完毕后将值传递给外部的查询.
相关子查询:
- 相关子查询的执行依赖于外部的查询数据, 外部查询执行一次, 子查询就会执行一次.
[所以非相关子查询比相关子查询效率高]
# `char` 和 `varchar` 的区别
- char` 类型的数据列里, 每个值都占 `M` 个字节, 如果长度小于 `M`, 就会在它的右边用空格字符进行补足 (在检索操作中填补出来的空格符将会被去掉).
- `vachar` 类型的数据列里, 每个值只占用刚好够用的字节再加上一个用来记录长度的字节, 所以总长度为 `L+1` 字节.
# `SQL` 问题
- 脏读
- 在一个事务处理过程中读取到了另一个未提交事务中的数据.
[例子]
A 在一个转账事务中, 转了 100 给 B, 此时 B 读到了这个转账的数据, 然后做了一些操作 (给 A 发货, 或是其他), 可是这个时候 A 的事务并没有提交, 如果 A 回滚了事务, 那这就是脏读.
- 不可重复读
- 对数据库中的某个数据, 一个事务范围内多次查询却返回了不同的数据值, 是由于在查询间隔, 被另一个事务修改并提交了.
[例子]
事务 A 在读取某一数据, 而事务 B 立马修改了这个数据并且提交了事务到数据库, 事务 A 再次读取就得到了不同的结果. 发生了不重复读.
- 幻读
- 事务非独立执行时发生的一种现象.
[例子]
事务 A 对一个表中所有的行的某个数据项做了从 "1" 修改为 "2" 的操作, 这时事务 B 又对这个表中插入了一行数据项, 这个数据的数值还是 "1" 并且提给了数据库, 如果事务 A 查看刚刚修改的数据, 会发现还有一数据没有修改, 而这行数据时事务 B 中添加的, 就像产生的幻觉一样. 发生了幻读.
# `MySQL` 事务隔离级别
1. `read uncmmited`: 读到未提交数据
- 最低级别, 无法保证任情况
2. `read commited`: 读已提交
- 可避免脏读
3. `repeatable read`: 可重复读
- 可避免脏读, 不可重复读
4. `serializable`: 串行事务
- 可避免脏读, 不可重复读, 幻读
**[`MySQL` 默认事务隔离级别为 `Repeatable Read`(可重复读)] **
# `MySQL` 临时表
什么是临时表: 临时表是 `MySQL` 用于存储中间结果集的表, 临时表只在当前连接可看, 当连接关闭时会自动删除表并释放所有空间.
为什么会产生临时表: 一般是因为复杂的 `SQL` 导致临时表被大量创建
- 进行 `union` 查询时
- 用到 `temptable` 算法或者是 `union` 查询中的视图
- `ORDER BY` 和 `GROUP BY` 的子句不一样时
- 表连接中,`ORDER BY` 的列不是驱动表中的
- `DISTINCT` 查询并且加上 `ORDER BY` 时
- `SQL` 中用到 `SLQ_SMALL_RESULT` 选项时
- `RROM` 中的子查询
临时表分为俩种:
- 内存临时表
- 采用的是 `memory` 存储引擎
- 磁盘临时表
- 菜用的是 `myisam` 存储引擎
# 什么是视图, 游标是什么?
视图: 视图是一种虚拟表, 具有和物理表相同的功能. 可以对视图表进行增删改查操作, 视图通常是有一个表或者多个表的子集. 对视图的修改不会影响基本表.
- [使得我们获取数据更容易, 相比多表查询]
游标: 是对查询出来的结果集作为一个单元来有效的处理. 游标可以定在该单元的特定行, 从结果集的当前行检索一行或多行. 可以对结果集当前行进行修改.
- [一般不会使用, 但需要逐条处理数据的时候, 游标显得十分重要]