MySQL基础知识汇总

268 阅读7分钟

drop、truncate、 delete区别

  • delete和truncate仅仅删除表数据,而drop可以删除表数据和表结构
  • truncate之后,这张表和索引占用的空间会恢复到初始大小;delete不会减少表和索引占用的空间;drop是将表所占用空间全部释放掉
  • 删除速度:drop>truncate>delete
  • delete是DML操作,可以进行回滚操作;drop,truncate是DDL操作,不能回滚。
  • 参考文章

数据库三大范式

第一范式(1NF)

定义:每一列都是不可分割的原子项

例:一个表:【联系人】(姓名,性别,电话)

如果在实际场景中,一个联系人有家庭电话和公司电话,那么这种表结构设计就没有达到1NF。

解决方案:

要符合1NF我们只需把列(电话)拆分,即:【联系人】(姓名,性别,家庭电话,公司电话)。1NF很好辨别,但是2NF和3NF就容易搞混淆。

第二范式(2NF)

定义:是在第一范式基础上的。有主键,要求实体的属性完全依赖于主键关键字。所谓完全依赖是指不能存在仅依赖主关键字的一部分的属性

例:一个订单明细表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。

因为我们知道在一个订单中可以订购多种产品,所以单单一个OrderID是不足以成为主键的,主键应该是(OrderID,ProductID)。

显而易见Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),

而UnitPrice,ProductName只依赖于ProductID。所以OrderDetail表不符合2NF。不符合2NF的设计容易产生冗余数据。

解决方案:

可以把【OrderDetail】表拆分为【OrderDetail】(OrderID,ProductID,Discount,Quantity)和

【Product】(ProductID,UnitPrice,ProductName)来消除原订单表中UnitPrice,ProductName多次重复的情况。

第三范式(3NF)

定义:任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖); 即不能存在:非主键列A依赖于非主键列B,非主键非主键列必须直接依赖于主键,不能存在传递依赖。列B依赖于主键的情况。

例:一个订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID)。

其中OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity等非主键列都完全依赖于主键(OrderID),所以符合2NF。

不过问题是CustomerName,CustomerAddr,CustomerCity直接依赖的是CustomerID(非主键列),而不是直接依赖于主键,

它是通过传递才依赖于主键,所以不符合3NF。

解决方案:

通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和

【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到3NF。

第二范式和第三范式对比

  • 2NF:非主键列是否完全依赖于主键,还是依赖于主键的一部分; 
  • 3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。


union和union all有什么不同

UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。

UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。

从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL。

SQL语句执行顺序

  • FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
  • ON: 对虚表VT1进行ON筛选,只有那些符合<join-condition>的行才会被记录在虚表VT2中。
  • JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
  • WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表VT4中。
  • GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
  • CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
  • HAVING: 对虚拟表VT6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表VT7中。
  • SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。
  • DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
  • ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.
  • LIMIT: 取出指定行的记录,产生虚拟表VT11, 并将结果返回。
  • 具体看这篇文章

    MVCC

    MVCC是为了实现事务的隔离性,通过版本号,避免同一数据在不同事务间的竞争。用简单的话讲就是对数据库的任何修改的提交都不会直接覆盖之前的数据,而是产生一个新的版本与老版本共存,使得读取时可以完全不加锁。这样读某一个数据时,事务可以根据隔离级别选择要读取哪个版本的数据。过程中完全不需要加锁。

    • MVCC是被Mysql中 事务型存储引擎InnoDB 所支持的;
    • 应对高并发事务, MVCC比单纯的加锁更高效;
    • MVCC只在读已提交和可重复读两个隔离级别下工作;
    • 各数据库中MVCC实现并不统一

    事务隔离级别

    为什么需要隔离?如果事务之间不是互相隔离的,可能将会出现以下问题:脏读,不可重复读,幻读

    脏读

    脏读:简单来说,就是一个事务在处理过程中读取了另外一个事务未提交的数据


    不可重复读

    不可重复读:是指一个事务范围内,多次查询某个数据,却得到不同的结果,侧重于修改


    幻读

    幻读:是事务非独立执行时发生的一种现象,侧重于新增或删除


    为了解决上面可能出现的问题,我们就需要设置隔离级别,也就是事务之间按照什么规则进行隔离,将事务隔离到什么程度。
    首先,需要明白一点,隔离程度越强,事务的执行效率越低。
    标准隔离级别:
    Serializable(串行化):花费最高代价但最可靠的事务隔离级别。
    “写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
    事务 100% 隔离,可避免脏读、不可重复读、幻读的发生。
    Repeatable read(可重复读,mysql默认级别):多次读取同一范围的数据会返回第一次查询的快照,即
    使其他事务对该数据做了更新修改。事务在执行期间看到的数据前后必须是一致的。
    但如果这个事务在读取某个范围内的记录时,其他事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行,这就是幻读。
    可避免脏读、不可重复读的发生。但是可能会出现幻读。
    Read committed (读已提交):保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。
    可避免脏读的发生,但是可能会造成不可重复读。
    大多数数据库的默认级别就是 Read committed,比如 Sql Server , Oracle。

    Read uncommitted (读未提交):最低的事务隔离级别,一个事务还没提交时,它做的变更就能被别的事务看到。


    隔离级别 脏读 不可重复读 幻读
    Read Uncommited Yes Yes Yes
    Read Committed No Yes Yes
    Repeatable Read No No Yes
    Serializable No No No


    MySQL如何解决幻读

    zhuanlan.zhihu.com/p/38218305

    www.jb51.net/article/159…

    blog.csdn.net/u013067756/…