数据库约束-数据库表设置0到100约束
前言
下面记录一些关于MySQL一些常见的问题
目录
数据库三大范式
MySQL存储引擎Mylsam和InnoDB有哪些区别
什么是索引?都有哪些类型?有什么优点和缺点?
B树和B+树的区别,聚簇索引和非聚簇索引的区别。什么是回表,怎么减少回表?
为什么会有索引失效的情况,索引调优有哪些方法?
MySQL中的锁有哪些?什么是next-key lock?
乐观锁与悲观锁
MySQL的事务隔离级别有哪些?MVCC是什么?
脏读,幻读,不可重复读是什么?是怎么解决的。
读已提交、可重复读、串行化分别是如何实现的?
MySQL删除数据时的一些注意事项。
MySQL使用时的一些经验和优化。
1. 数据库三大范式
总结:这三个范式的目的是为了消除数据冗余、提高数据的完整性和一致性,保证数据的正确性和稳定性。
2. MySQL存储引擎Mylsam和InnoDB有哪些区别
事务支持:InnoDB支持事务,而MyISAM不支持事务。
锁级别:MyISAM在执行SELECT语句时,会对需要读取的数据表进行整表锁定,而InnoDB支持行级锁和表级锁。
ACID属性:InnoDB是一个ACID兼容的存储引擎,它支持原子性、一致性、隔离性和持久性,而MyISAM则只支持持久性。
并发性:由于InnoDB支持行级锁,因此并发性能更好,同时也避免了表级锁带来的并发性问题。
外键支持:InnoDB支持外键,而MyISAM不支持。
数据缓存:InnoDB支持数据和索引的缓存,而MyISAM只支持索引的缓存。
适用场景:MyISAM适合于读取密集型的应用,例如数据仓库,而InnoDB适合于事务处理的应用,例如电子商务和银行系统。
总结:MyISAM和InnoDB各有优缺点,在实际应用中需要根据具体需求来选择使用哪种存储引擎
3. 什么是索引?都有哪些类型?有什么优点和缺点?
索引是一种用于提高数据库查询性能的数据结构。它类似于书中的目录,能够加速查找数据的速度,使得数据库查询更加高效。
索引的类型有很多种,主要包括以下几种:
B-Tree索引:是最常用的一种索引类型,它是一种基于B-Tree数据结构的索引,用于快速查找具有某些值的行。B-Tree索引支持精确查找和范围查找,并且在查询较小的数据集时效果最佳。
哈希索引:是一种基于哈希表的索引,用于快速查找具有某些值的行。哈希索引仅支持精确查找,不能进行范围查找,但是在查询大数据集时,哈希索引比B-Tree索引更快。
全文索引:是一种用于在文本数据中查找特定单词或短语的索引,支持模糊查询和关键词查询。
空间索引:是一种用于查找具有特定地理位置的行的索引,支持地理位置查询和空间关系查询。
索引的优点包括:
提高查询性能:索引可以加速数据的查找和读取,使得查询更加高效。
减少数据读取量:索引可以避免全表扫描,减少数据的读取量,降低数据库的负载。
优化数据库结构:索引可以优化数据库表的结构,提高数据库的整体性能。
索引的缺点包括:
增加存储空间:索引需要占用存储空间,如果索引过多或过长,会占用大量的存储空间。
降低更新性能:对于经常进行插入、删除和更新操作的表,索引的维护会降低更新操作的性能。
可能导致查询性能下降:如果索引选择不当或者过多,会导致查询性能下降,甚至出现死锁等问题。因此,在创建索引时需要根据实际情况进行优化和选择。
4. B树和B+树的区别,聚簇索引和非聚簇索引的区别。什么是回表,怎么减少回表?
B树和B+树都是多叉树的一种,它们都可以用于实现数据库中的索引。B树的节点中既包含了索引键,也包含了指向数据的指针;而B+树的节点只包含索引键,数据则全部存放在叶子节点中。具体区别如下:
B树中的每个节点都可以存放数据,而B+树的数据只存储在叶子节点中,而非中间节点。
B+树中叶子节点之间有一个链表相连,因此可以很方便地进行范围查找和遍历。
B+树相较于B树更加适合在磁盘等外存储介质上使用,因为B+树的内部节点存放的只是关键字,而不存储数据,可以减少I/O操作。
聚簇索引和非聚簇索引的区别:聚簇索引是将数据存储与索引放在一起的索引方式,也就是说,聚簇索引的叶子节点就是数据页,数据页的顺序与索引页的顺序相同。非聚簇索引则是将数据和索引分别存储在不同的文件中。
区别如下:
聚簇索引在查询时可以直接找到数据行,速度较快,而非聚簇索引需要进行两次查找,先查找索引,再通过索引找到数据行,速度相对较慢。
聚簇索引只能有一个,因为数据与索引存储在一起,而非聚簇索引可以有多个。
聚簇索引只能建立在主键或唯一约束上,而非聚簇索引可以建立在任何列上
回表和如何减少回表:在数据库查询时,如果需要查询的列不在索引中,或者需要查询的列在非聚簇索引中,但是需要通过非聚簇索引再次查找数据行,则称为回表。回表会增加额外的I/O操作,降低查询效率。
减少回表的方法如下:
尽可能地使用聚簇索引:聚簇索引可以减少回表的次数,提高查询效率。考虑使用覆盖索引:覆盖索引是指包含查询所需的所有数据的索引,因此查询时不需要回表。
尽可能地减少查询的列:只查询需要的列,不查询不需要的列,可以减少回表的次数。
优化SQL语句:编写高效的SQL语句,避免使用
5. 为什么会有索引失效的情况,索引调优有哪些方法?
索引失效通常是由于查询语句中的条件与索引不匹配而导致的。以下是一些常见的导致索引失效的情况:
不使用索引列:如果查询语句没有使用索引列,那么索引就无法发挥作用,查询将会全表扫描,效率低下。
在索引列上使用函数:如果查询语句在索引列上使用了函数,如使用了LOWER()函数将查询条件转换为小写,那么索引就无法被使用,查询将会全表扫描。
对索引列进行运算:如果查询语句对索引列进行了运算,如使用了+运算符将两个列相加作为查询条件,那么索引也无法被使用。
条件使用OR:如果查询语句中的条件使用了OR运算符连接多个条件,而这些条件只有部分可以使用索引,那么索引也无法被使用。
为了避免索引失效,可以考虑以下索引调优的方法:
确保查询语句使用索引列:查询语句应该使用索引列作为条件,这样索引才能被使用。
避免在索引列上使用函数或运算符:在查询语句中避免在索引列上使用函数或运算符,如果必须使用函数或运算符,可以考虑在查询之前对数据进行预处理,将结果存储到新的列中,然后使用这些新的列进行查询。
考虑使用复合索引:如果查询语句中有多个条件,可以考虑使用复合索引,将多个条件都包含在一个索引中。
使用索引覆盖查询:如果查询语句只需要返回索引列的值,可以使用索引覆盖查询,这样可以避免对表进行全表扫描。
使用合适的数据类型:在创建表时,应该使用合适的数据类型,这样可以提高索引效率,减少索引失效的概率。
总结:索引调优是一个复杂的过程,需要根据具体情况进行优化,以提高数据库的性能和效率。
6. MySQL中的锁有哪些?什么是next-key lock?
MySQL中的锁主要分为共享锁和排他锁两种。
共享锁(Shared Lock):共享锁又称为读锁,多个事务可以同时持有共享锁,并发读取同一份数据,不会互相影响,但是不能进行写操作。当一个事务持有共享锁时,其他事务只能获取共享锁,而不能获取排他锁。
排他锁(Exclusive Lock):排他锁又称为写锁,只能被一个事务持有,当一个事务持有排他锁时,其他事务无法获取共享锁或排他锁,只能等待该事务释放锁。排他锁既可以进行读操作,也可以进行写操作。
在MySQL中,使用next-key lock来实现范围查询时的加锁机制,即行锁和间隙锁的组合,也称为Next-Key锁。它是在InnoDB存储引擎中实现的,用于避免幻读问题。
当执行范围查询时,InnoDB会在满足条件的记录上加上行锁,同时在记录之间的间隙上加上间隙锁,这样可以避免其他事务插入符合条件的记录。这种锁的组合称为Next-Key锁。
举个例子:假设有一个表,包含3条记录:A、B、C。执行以下查询:
SELECT * FROM table WHERE id > 1 AND id < 4;
InnoDB会在记录B上加上行锁,并在记录A和记录C之间的间隙上加上间隙锁,这样其他事务无法插入id为2或3的记录。
需要注意的是,Next-Key锁只在repeatable read和read committed隔离级别下使用,在read uncommitted和SERIALIZABLE隔离级别下,使用的是间隙锁或行锁,而不是Next-Key锁。
7. 乐观锁与悲观锁
乐观锁和悲观锁是两种不同的并发控制机制,主要用于多个用户并发访问共享资源时保证数据的一致性。
悲观锁:悲观锁是一种较为保守的并发控制方式。它认为并发访问时一定会出现冲突,因此在访问共享资源时先加锁,确保自己独占资源,防止其他并发访问的线程对该资源进行修改。悲观锁主要使用数据库中的行级锁或表级锁实现。悲观锁的缺点是会影响系统的并发性能,尤其是在高并发的情况下。
乐观锁:乐观锁相对于悲观锁来说,它是一种乐观的并发控制方式。它认为并发访问时不会出现冲突,因此在访问共享资源时并不加锁,而是通过版本号等机制判断数据是否被修改。如果没有被修改,则允许操作;如果已经被修改,则不允许操作,需要进行相应的处理。乐观锁主要使用CAS(Compare And Swap)等算法实现。乐观锁的优点是可以提高系统的并发性能,但是在并发更新高的情况下容易出现ABA问题。
ABA问题:ABA问题指的是在使用乐观锁进行并发控制时,由于共享资源被修改多次而导致的数据不一致问题。具体来说,如果有两个线程T1和T2同时读取一个共享变量V,T1先执行了一个操作将V的值由A变成了B,然后又将V的值由B变成了A;此时T2也开始执行,并且在T1的操作完成之后将V的值由A变成了C,然后又将V的值由C变成了A。此时,T1再次读取V的值时,仍然是A,虽然V的值没有被其他线程修改过,但是T1并不知道V的值已经被其他线程修改过,因此可能会误认为V的值没有被修改过,从而出现数据不一致的问题。
为了解决ABA问题,可以采用如下两种方式:
使用带有版本号的原子变量,每次更新时都将版本号加1。这样,在判断时不仅要判断值是否相等,还要判断版本号是否相等。
使用ABA问题的预防方案,例如使用读写锁或者采用悲观锁。在采用悲观锁的情况下,每次读取共享资源时都需要加锁,这样可以保证其他线程不能修改共享资源,从而避免了ABA问题的出现。
总结:乐观锁和悲观锁都是为了保证并发访问共享资源的数据一致性,但是它们的实现方式和适用场景不同。一般来说,在并发更新较少的情况下,可以采用乐观锁,可以提高系统的并发性能;而在并发更新较多的情况下,为了保证数据的一致性,可以采用悲观锁。
8. MySQL的事务隔离级别有哪些?MVCC是什么?
MySQL的事务隔离级别有以下4种:
读未提交(Read Uncommitted):允许一个事务读取另一个事务未提交的数据。这种隔离级别存在脏读、不可重复读和幻读的问题。
读已提交(Read Committed):要求一个事务只能读取另一个事务已经提交的数据。这种隔离级别解决了脏读的问题,但是仍然存在不可重复读和幻读的问题。
可重复读(Repeatable Read):保证在同一个事务中多次读取同一数据时,读取到的数据是一致的。这种隔离级别解决了不可重复读的问题,但是仍然存在幻读的问题。
串行化(Serializable):最高的隔离级别,强制事务串行执行,避免了幻读的问题,但是会影响并发性能。
MVCC是MySQL中实现多版本并发控制的一种机制,它是在可重复读隔离级别下实现的。MVCC将每一行数据看作一个版本,每个版本都有一个版本号和时间戳。读取操作只能读取时间戳小于等于当前事务时间戳的版本,写入操作会创建一个新的版本,并更新时间戳和版本号。这样可以实现多个事务同时对同一数据进行读操作,而不会相互影响,从而提高了并发性能。同时,MVCC还可以保证在可重复读隔离级别下不会出现幻读的问题。
9. 脏读,幻读,不可重复读是什么?是怎么解决的。
脏读(Dirty Read)指的是一个事务读取到了另一个事务未提交的数据,如果另一个事务回滚,则读取到的数据是无效的。脏读问题可以通过设置事务隔离级别为“读已提交”(Read Committed)来解决。
幻读(Phantom Read)指的是一个事务读取到了另一个事务在同一个范围内插入的数据,导致第一个事务后续查询的结果集不一致。幻读问题可以通过设置事务隔离级别为“可重复读”(Repeatable Read)或“串行化”(Serializable)来解决。
不可重复读(Non-repeatable Read)指的是一个事务多次读取同一数据,在事务执行过程中另一个事务对数据进行了修改,导致第一个事务多次读取同一数据时读取到的数据不一致。不可重复读问题可以通过设置事务隔离级别为“可重复读”(Repeatable Read)或“串行化”(Serializable)来解决。
解决以上问题的方法如下:
脏读问题可以通过将事务隔离级别设置为“读已提交”(Read Committed)来避免。
不可重复读问题可以通过将事务隔离级别设置为“可重复读”(Repeatable Read)或“串行化”(Serializable)来避免。
幻读问题可以通过将事务隔离级别设置为“可重复读”(Repeatable Read)或“串行化”(Serializable),或者使用行级锁或表级锁来解决。
10. 读已提交、可重复读、串行化分别是如何实现的?
它们分别通过不同的机制来实现数据的并发访问:
读已提交(Read Committed):该隔离级别要求一个事务只能读取另一个事务已经提交的数据。它通过在读取数据时加锁,保证读取到的数据是当前已提交的版本,而不会读取到未提交的脏数据。在该隔离级别下数据库约束,其他事务可以修改数据,因此可能会出现不可重复读和幻读问题。
可重复读(Repeatable Read):该隔离级别保证在同一个事务中多次读取同一数据时,读取到的数据是一致的。它通过在事务启动时记录当前时间戳,然后在读取数据时只读取时间戳小于等于当前时间戳的版本。在该隔离级别下,其他事务可以插入新数据,但不能修改已有数据,因此不会出现不可重复读问题数据库约束,但仍可能出现幻读问题。
串行化(Serializable):该隔离级别是最严格的隔离级别,它强制事务串行执行,避免了所有并发问题,但会影响性能。它通过在读取数据时对所有访问的数据加锁,防止其他事务对数据进行修改或插入,从而保证了数据的一致性和唯一性。
需要注意的是,在可重复读隔离级别下,可能仍然存在幻读的问题,因为InnoDB只对已有的数据行生成多个版本,而对于新插入的数据行则没有生成多个版本,因此,如果在事务中多次执行同一个查询,可能会看到不同的结果集。如果需要完全避免幻读问题,则需要使用串行化隔离级别。
11. MySQL删除数据时的一些注意事项。
在MySQL中,删除数据是一个常见的操作,但是需要注意以下一些事项:
使用事务:在进行数据删除操作时,建议使用事务来保证数据的一致性和完整性。如果删除一条记录时出现问题,事务可以回滚到删除之前的状态,避免数据丢失或不一致的情况发生。
慎用DELETE语句:DELETE语句会直接删除表中的数据,因此需要慎重使用。如果误删了数据,就无法恢复了。在删除数据之前,可以使用SELECT语句先查看一下将要删除的数据是否正确。
使用带WHERE子句的DELETE语句:如果不带WHERE子句执行DELETE语句,将会删除表中的所有数据,这是一种非常危险的操作。因此,执行DELETE语句时必须要带上WHERE子句,确保只删除符合条件的数据。
禁用TRUNCATE语句:TRUNCATE语句会删除整张表的数据,而且没有回滚操作,因此需要慎重使用。如果需要清空表中的数据,建议使用DELETE语句。
禁止在应用程序中使用DELETE FROM语句:在应用程序中使用DELETE FROM语句会导致大量的I/O操作和锁竞争,从而影响系统的性能。因此,建议使用
TRUNCATE或者DROP TABLE来清空表中的数据。使用LIMIT子句:在执行DELETE语句时,建议使用LIMIT子句来限制删除的数据条数。如果不使用LIMIT子句,可能会导致删除整个表的数据。
优化DELETE语句:在执行DELETE语句时,可以使用索引来优化查询速度,避免全表扫描。如果删除的数据很多,可以考虑分批删除,每次删除一部分数据,避免锁表和I/O问题。
12. MySQL使用时的一些经验和优化