第一章:索引、事务和锁

索引

1.什么是索引?

是存储引擎快速找到记录的一种数据结构类似于我们常用的新华字典中的目录,以便于更快的查找的所需的内容

2. 为什么要有索引?

为了对表格进行更快的查询

3. 索引的优、劣势

优势: 可以快速检索,减少 I/O 次数,加快检索速度;根据索引分组和排序,可以加快分组和排序。
劣势:索引表占用的空间是数据表的1.5倍; 维护和创建需要时间成本,而且这个成本会随着数据增大而增大,构建索引表会降低数据表的修改操作(增、删、改)的效率。

4. 索引的使用

4.1创建索引
一、创建表时语法: index 索引名(字段)

create table  mytable(
	id int not null,
	username varchar(16) not null,
	index myindex(username(16))
	);
	说明:myindex为自定义索引名称,index:表示索引

二、创建表之后创建索引语法:

1.create index  索引名 on 表名(字段);
create  index myindex on mytable(uername(16));`
2.alter table 表名 add index 索引名 (字段名);
alter table mytable ADD index myindex(username);

三、查看索引
语法: show index from 表名

show index from  mytable

四、删除索引语法

1.drop index 索引名 on 表名
drop index myindex on mytable;
2.alter table  表名 drop index 索引名
alter table mytable drop index myindex;

五、通过 explain 命令查看索引使用情况

explain select * from mytable where username = 'jack';

5.索引的使用规则

索引的分类

  • 主键索引
    主索引,根据主键pk_colum(length)建立索引,不允许重复,不允许空值
  • 唯一索引
    用来建立索引的列的值必须是唯一的,允许空值 ;
  • 普通索引
    用表中的普通列构建的索引,没有任何限制
  • 全文索引
    用大文本对象的列构建的索引这多个列中的值不允许为空
  • 组合索引
    用多个列组合构建的索引,这个列中的值不允许有空值。

二、适合建立索引的情况

  • 主键自动建立唯一索引;
  • 经常作为查询条件在 WHERE 或者 ORDER BY 语句中出现的列要建立索引;
  • 作为排序的列要建立索引;
  • 查询中与其他表关联的字段,外键关系建立索引;
  • 高并发条件下倾向组合索引;
  • 用于聚合函数的列可以建立索引;
    例如:使用了 max(column_1)或者 count(column_1)时的 column_1 就需 要建立索引。

三、不适合建立索引的情况

  • 经常增删改的列不要建立索引
  • 有大量重复的列不建立索引;
  • 表记录太少不要建立索引;
    只有当数据库里已经有了足够多的测试数据时,它的性能测试结果才有实际 参考价值。如果在测试数据库里只有几百条数据记录,它们往往在执行完第一条查询命令之后就被全部 加载到内存里,这将使后续的查询命令都执行得非常快–不管有没有使用索引。只有当数据库里的记录 超过了 1000 条、数据总量也超过了 MySQL 服务器上的内存总量时,数据库的性能测试结果才有意义。

四、索引失效的情况

  • 在组合索引中不能有列的值为 NULL,如果有,那么这一列对组合索引就是无效的;
  • 在一个 SELECT 语句中,索引只能使用一次,如果在 WHERE 中使用了,那么在 ORDER BY 中就不要用了;
  • LIKE 操作中,’%aaa%'不会使用索引,也就是索引会失效,但是‘aaa%’可以使用索引;a
  • 在索引的列上使用表达式或者函数会使索引失效;
  • 在查询条件中使用不等于,包括<符号、>符号和!=会导致索引失效;
  • 在查询条件中使用 IS NULL 或者 IS NOT NULL 会导致索引失效;
  • 字符串不加单引号会导致索引失效;
  • 在查询条件中使用 OR 连接多个条件会导致索引失效,除非 OR 链接的每个条件都加上索引;
  • 如果排序的字段使用了索引,那么 select 的字段也要是索引字段,否则索引失效;
  • 尽量不要包括多列排序,如果一定要,最好为这队列构建组合索引。
    注意: 具体查看索引是否有效,可以使用explain命令查询
    通过 explain 命令查看索引使用情况
explain select * from mytable where username = 'jack';

事务

一、什么是事务?

**
事务(Transaction):一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转 账业务,该业务就是一个最小的工作单元;事务只和 DML 语句有关,或者说 DML 语句才有事务。可以通过转账操作来理解事务。

二、MySQL中事务的使用方法

开启事务语法
start transaction;

SQLserver开启事务语法

begin transaction;

提交事务语法

commit;

回滚事务

rollback;

案例:

start transaction;-- 手动开启事务 
	insert into t_act values(3,300); -- 更新操作
	 commit;-- 提交事务,commit 之后即改变底层数据库数据 
	select * from t_act;

注:回滚事务会撤销更新操作

三、事务的特征

  • 原子性(A)
    事务是最小单位,不可再分;
  • 一致性©
    事务要求所有的 DML 语句操作的时候,必须保证同时成功或者同时失败;
  • 隔离性(I)
    同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰;
  • 持久性(D)
    是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中);

四、事务的并发操作

  • 脏读
    当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读------------读取心思
  • 不可重复读
    在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。------------无敌美颜
  • 幻读
    在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。------------男神翻倍

五、事务的隔离级别

  • 读未提交(read uncommintted):事务 A 和事务 B,事务 A 未提交的数据,事务 B 可以读取到,这里读 取到的数据叫做“脏数据”。这种隔离级别最低,一般是在理论上存在,数据库隔离级别一般都高于该 级别;(隔离级别最低,脏读,幻读,不可重复读都不可避免)
    使用语法
set  session transaction isolation level read uncommitted
  • 读已提交(read commintted):事务 A 和事务 B,事务 A 提交的数据,事务 B 才能读取到。这种隔离级 别高于读未提交,可以避免“脏数据”。但如果事务 A 多次读取同一数据,而事务 B 在事务 A 多次读 取的过程中,对数据作了更新并提交,导致事务 A 多次读取同一数据时,结果不一致,这种现象称为“不 可重复读”(避免不了不可重复读和幻读)
    使用语法
set  session transaction isolation level read committed
  • 可重复读(repeatable read):事务 A 和事务 B,事务 A 提交之后的数据,事务 B 读不到事务 A 提交 的数据。这种隔离级别高于读已提交,但如果事务 A 在修改数据的过程中(比如将所有记录状态设为 1), 如果事务 B 向同一张表中插入一条新记录(状态为 0),事务 A 提交后再次查询表,会发现有一条记录 状态没有改成 1,好像发生了幻觉,这种现象称为“幻读”。可重复读是 MySQL 默认隔离级别;(避免不了幻读)
    使用语法
    set session transaction isolation level repeatable read
  • 串行化(serializable):事务 A 和事务 B,事务 A 在操作数据库时,事务 B 只能排队等待。这种级别 可以避免“幻读”,每一次读取的都是数据库中真实存在数据,事务 A 与事务 B 串行,而不并发。(可避免脏读,幻读,不可重复读)
    使用语法
    set session transaction isolation level serializable
    注:隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得
  • 事务的隔离级别与一致性关系图

一、什么是锁?

锁是计算机协调多个进程或线程并发访问某一资源的机制,如何保证数据并发访问的一致性、有效性是所有数 据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。

二、锁的作用:防止资源不浪费

三、悲观锁和乐观锁

  • 乐观锁
    什么是乐观锁?
    乐观锁是指操作数据库时(更新操作),想法很乐观,认为 这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后, 再去判断是否有冲突了
  • 悲观锁
    什么是悲观锁
    悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次 操作时都要通过获取锁才能进行对相同数据的操作,因此悲观锁需要较多的时间,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相 关语句就可以了

四、锁的实现

1、共享锁与排它锁
  • 共享锁(S)
    也称为读锁,允许事务读取一行数据。例如事务 T 对数据对象 A 加上 S 锁,则事务 T 可以读 A 但不能修改 A,其他事务只能再对 A 加 S 锁,而不能加 X 锁,直到 T 释放 A 上的 S 锁。这保证了其他事务可以读 A,但在 T 释放 A 上的 S 锁之前不能对 A 做任何修改
  • 排它锁(X)
    也称写锁,允许事务删除或更新一行数据。例如事务 T 对数据对象 A 加上 X 锁,事务 T 可以读 A 也可以修改 A,其他事务不能再对 A 加任何锁,直到 T 释放 A 上的锁。

2.锁的粒度:锁的粒度就是你要锁定的范围是多大。使用锁时,锁定的东西越少,对其他竞争者影响越小,这个东西的大 小就是锁粒度。
3.锁的粒度分类

  • 表级锁
    开销小,加锁快,不会出现死锁。锁定粒度最大,适合查询为主的,只有少量按索引条件更新 数据的操作。缺点是资源争用概率高
  • 行级锁
    开销大,加锁慢,会出现死锁。锁定粒度最小,适合大量按索引条件并发更新少量不同数据,同时又有并发查询的操作。使用行级锁定的主要是 InnoDB 存储引擎;
  • 页面锁
    开销介于表锁与行锁之间,会出现死锁

提示:因为悲观锁是由数据库实现的,一般不需要开发人员操作,我们只需要了解锁的作用与分类以及 锁和事务的关系就可以了
注:共享锁之间是兼容的,而排它锁与其他任意锁都不兼容。因此我们在数据库中可以并行读,但只 能串行写,只有这样才不会发生线程竞争