一:MySQL 索引介绍
索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址。在数据十分庞大的时候,索引可以大大加快查询的速度。这是因为使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据。
1.1:索引概述
以如果需要在一个无序字段上进行搜索,就要执行一个线性搜索(Linear Search)的过程,平均需要访问 N/2 的数据块,N 是表示所占据的数据块数目。如果这个字段是一个非主键字段(也就是说,不包含唯一的访问入口),那么需要在 N 个数据块上搜索整个表格空间
但是对于一个有序字段,可以运用二分查找(Binary Search),这样只需要访问 log2 (N)的数据块。
索引是对记录集的多个字段进行排序的方法。在一张表中为一个字段创建一个索引,将创建另外一个数据结构,包含字段数值以及指向相关记录的指针,然后对这个索引结构进行排序,允许在该数据上进行二分法排序。使用索引的副作用是需要额外的磁盘空间。
备注:
Log2N是数学中的对数,是以2为底N的对数为多少,也就是2的多少次方是N
备注:
线性搜索:线性搜索是在列表中查找元素的基本算法。 它依次检查列表的每个元素,直到找到目标元素或确定目标不存在。 线性搜索也称为蛮力搜索,因为它检查列表中的每个元素,而不管是否检查了任何先前的元素。
- 索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于C语言的链表通过指针指向数据记录的内存地址)
- 使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据,因此能加快数据库的查询速度。
- 索引就好比是一本书的目录,可以根据目录中的页码快速找到所需的内容。
- 索引是表中一列或者若干列值排序的方法
- 建立索引的目的是加快对表中记录的查找或排序
1.2:索引作用
数据库利用各种各样的快速定位技术,能够大大提高查询效率。特别是当数据量非常大,查询涉及多个表时,使用索引往往能使查询速度加快成千上万倍。
优点
- 设置了合适的索引之后,数据库利用各种快速定位技术,能够大大加快查询速度,这是创建索引的最主要的原因。
- 当表很大或查询涉及到多个表时,使用索引可以成千上万倍地提高查询速度。
- 可以降低数据库的IO成本,并且索引还可以降低数据库的排序成本。
- 通过创建唯一性索引,可以保证数据表中每一行数据的唯一性。
- 可以加快表与表之间的连接。
- 在使用分组和排序时,可大大减少分组和排序的时间。
1.3:索引的分类
创建测试数据库和表
mysql> create database auth;
mysql> use auth
mysql> create table users (id int(10),user_name char(20),user_pass char(50));
1:普通索引
普通索引是最基本的索引,它没有任何限制,也是大多数情况下用到的索引。
(1)直接创建索引语法
mysql>CREATE INDEX index_name ON table_name(column(length));
例:
mysql> create index aaa on users(user_name(20));
备注
其中 length 是可选项。如果忽略 length 的值,则使用整个列的值作为索引。如果指定使用列前的 length 个字符来创建索引,就是使用列的一部分来创建索引,这样有利于减小索引文件的大小,节省索引列所占的空间。在某些情况下,只能对列的前缀进行索引。索引列的长度有一个最大上限 255 个字节(MyISAM 和 InnoDB 表的最大上限为 1000 个字节),如果索引列的长度超过了这个上限,就只能用列的前缀进行索引。另外,BLOB(二进制大对象)或TEXT(文本)类型的列也必须使用前缀索引。
注意:
数字类型的列不能指定其长度,字符串的可以
(2)修改表结构的方式添加索引语法
mysql>ALTER TABLE table_name ADD INDEX index_name (column(length));
例:
mysql> drop index aaa on users;
mysql> alter table users add index aaa (user_pass(45));
注意:
45是为该字段定义的字符长度,只能比初始值小,不能比初始值大
(3)创建表结构时,同时创建索引
【例】创建table01表,指定title列为普通索引
CREATE TABLE table01 (
id int(11) NOT NULL AUTO_INCREMENT ,
title char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
content text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
time int(10) NULL DEFAULT NULL ,
PRIMARY KEY (id),
INDEX index_table01_title (title(11))
);
【例】在book表中的year_publication字段上建立普通索引,SQL语句如下:
(1)创建表结构时,同时创建索引
mysql> use auth;
CREATE TABLE book
(
bookid INT NOT NULL,
bookname VARCHAR(255) NOT NULL,
authors VARCHAR(255) NOT NULL,
info VARCHAR(255) NULL,
comment VARCHAR(255) NULL,
year_publication YEAR NOT NULL,
INDEX(year_publication)
);
mysql> SHOW CREATE table book \G
*************************** 1. row ***************************
Table: book
Create Table: CREATE TABLE `book` (
`bookid` int(11) NOT NULL,
`bookname` varchar(255) NOT NULL,
`authors` varchar(255) NOT NULL,
`info` varchar(255) DEFAULT NULL,
`comment` varchar(255) DEFAULT NULL,
`year_publication` year(4) NOT NULL,
KEY `year_publication` (`year_publication`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
(2)直接创建索引
mysql> create index aaa on book(bookid);
(3)修改表结构的方式添加索引语法
mysql> alter table book add index bbb(bookname(255));
2:唯一索引
唯一索引与普通索引类似,不同的就是:唯一索引的索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一。
(1)创建唯一索引语法
mysql>CREATE UNIQUE INDEX index_name ON table_name(column(length));
(2)修改表结构的时候添加唯一索引语法
mysql>ALTER TABLE table_name ADD UNIQUE index_name (column(length));
(3)创建表的时候同时创建唯一索引
CREATE TABLE table02 (
id int(11) NOT NULL AUTO_INCREMENT ,
title char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
content text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
time int(10) NULL DEFAULT NULL ,
PRIMARY KEY (id),
UNIQUE index_table02_title (title(11))
);
【例】创建一个表t1,在表中的id字段上使用UNIQUE关键字创建唯一索引。
(1)创建表的时候同时创建唯一索引
CREATE TABLE t1
(
id INT NOT NULL,
name CHAR(30) NOT NULL,
UNIQUE INDEX UniqIdx(id)
);
mysql> SHOW CREATE table t1 \G
*************************** 1. row ***************************
Table: t1
CREATE Table: CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`name` char(30) NOT NULL,
UNIQUE KEY `UniqIdx` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
由结果可以看到,id字段上已经成功建立了一个名为UniqIdx的唯一索引。
(2)创建唯一索引语法
mysql> create unique index ccc on t1(id);
(3)修改表结构的时候添加唯一索引语法
MariaDB [test]> alter table t1 add unique ddd(id);
3:主键索引
主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引。
创建主键索引语法
CREATE TABLE table_name (
id int(11) NOT NULL AUTO_INCREMENT ,
title char(255) NOT NULL ,
PRIMARY KEY (id)
);
【例】创建表t2,并将表中的id列设为主键
CREATE TABLE t2
(
id int(11) NOT NULL AUTO_INCREMENT ,
title char(255) NOT NULL ,
PRIMARY KEY (id)
);
mysql> SHOW CREATE table t2 \G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
4:组合索引(最左前缀)
平时用的 SQL 查询语句一般都有比较多的限制条件,所以为了进一步榨取 MySQL 的效率,就要考虑建立组合索引。在组合索引的创建中,有两种场景,即为单列索引和多列索引。
【例】在一个t3用户表中,有 name,age,sex 三个字段,分别分三次建立了 INDEX 普
通索引。那么在 select * from user where name = '' AND age = '' AND sex = '';数据查询语
句中就会分别检索三条索引,虽然扫描效率有所提升,但却还未达到最优。这个时候就需要
使用到组合索引(即多列索引)。
create table t3
(
name varchar(9),
age int(3),
sex tinyint(1),
index eee(name, age, sex)
);
注意:
select 语句的 where 条件是依次从左往右执行的。
mysql>select * from user where name = '' AND age = '' AND sex = '';
若使用的是组合索引 index user(name, age, sex)。在查询中,name、age、sex 的顺序必须如组合索引中一致排序,否则索引将不会生效。
5:全文索引(FULLTEXT)
在1M大小的文件中搜索一个词,可能需要几秒,在100M的文件中可能需要几十秒,如果在更大的文件中搜索那么就需要更大的系统开销,这样的开销是不现实的。
在数据库中常用的查询方式一般是等价,范围方式。当然也有LIKE %的模糊查询,虽然用不到索引,在文本内容比较少时是比较合适,但是对于大量的文本数据检索,全文索引在大量的数据面前,能比 LIKE % 快很多,速度不是一个数量级
(1)创建表的全文索引语法:
CREATE TABLE table (
id int(11) NOT NULL AUTO_INCREMENT ,
title char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
content text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
time int(10) NULL DEFAULT NULL ,
PRIMARY KEY (id),
FULLTEXT (content)
) ENGINE=MyISAM**;**
(2)修改表结构添加全文索引语法:
mysql>ALTER TABLE article ADD FULLTEXT index_content(content);
(3)直接创建索引语法:
mysql>CREATE FULLTEXT INDEX index_content ON article(content);
【例】创建表t4,在表中的info字段上建立全文索引,SQL语句如下:
CREATE TABLE t4
(
id INT NOT NULL,
name CHAR(30) NOT NULL,
age INT NOT NULL,
info VARCHAR(255),
FULLTEXT INDEX FullTxtIdx(info)
) ENGINE=MyISAM;
默认存储引擎为InnoDB,InnoDB不支持全文索引,在这里创建表时需要修改表的存储引擎为MyISAM,不然创建索引会出错。
语句执行完毕之后,使用SHOW CREATE TABLE查看表结构:
mysql> SHOW CREATE table t4 \G
*************************** 1. row ***************************
Table: t4
CREATE Table: CREATE TABLE `t4` (
`id` int(11) NOT NULL,
`name` char(30) NOT NULL,
`age` int(11) NOT NULL,
`info` varchar(255) DEFAULT NULL,
FULLTEXT KEY `FullTxtIdx` (`info`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
由结果可以看到,info字段上已经成功建立了一个名为FullTxtIdx的FULLTEXT索引。全文索引非常适合于大型数据集,对于小的数据集,它的用处可能比较小。
(2)修改表结构添加全文索引语法:
mysql> alter table t4 add fulltext fff(name);
(3)直接创建索引语法:
mysql> create fulltext index ggg on t4(info);
1.4:创建索引的原则依据
数据库建立索引的原则:
确定针对该表的操作是大量的查询操作还是大量的增删改操作;
尝试建立索引来帮助特定的查询。检查自己的 sql 语句,为那些频繁在 where 子句中出现的字段建立索引;
尝试建立复合索引来进一步提高系统性能。修改复合索引将消耗更长时间,同时复合索引也占磁盘空间;
对于小型的表,建立索引可能会影响性能;
应该避免对具有较少值的字段进行索引;
避免选择大型数据类型的列作为索引。
索引建立的原则:
索引查询是数据库中重要的记录查询方法,要不要建立索引以及在那些字段上建立索引都要和实际数据库系统的查询要求结合来考虑,下面给出实际生产环境中的一些通用的原则:
- 表的主键、外键必须有索引。因为主键具有唯一性,外键关联的是子表的主键,查询时可以快速定位。
- 记录数超过300行的表应该有索引。如果没有索引,需要把表遍历一遍,会严重影响数据库的性能。
- 经常与其他表进行连接的表,在连接字段上应该建立索引。
- 唯一性太差的字段不适合建立索引。
- 更新太频繁地字段不适合创建索引。
- 经常出现在 where 子句中的字段,特别是大表的字段,应该建立索引。索引应该建在选择性高的字段上。
- 索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引。
1.5:查看索引
mysql>show index from t1\G;
mysql>show keys from t2\G;
mysql>show create table t3 \G
1.6:删除索引
索引的删除有如下两种方法
DROP INDEX 索引名 ON 表名;
ALTER TABLE 表名 DROP INDEX 索引名;
【例】
mysql> drop index eee on t3;
mysql> alter table t1 drop index ccc;
注意:
删除前可以先用show命令查看一下表中的索引名
二:MySQL 事务
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,要删除一个人员,即需要删除人员的基本资料,又需要删除和该人员相关的信息,如信箱,文章等等。这样,这些数据库操作语句就构成一个事务。
是一种机制、一个操作序列,包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行
是一个不可分割的工作逻辑单元,在数据库系统上执行并发操作时,事务是最小的控制单元
适用于多用户同时操作的数据库系统的场景,如银行、保险公司及证券交易系统等等
通过事务的整体性以保证数据的一致性
事物的ACID特性
原子性(Atomicity)
- 事务是一个完整的操作,事务的各元素是不可分的
- 事务中的所有元素必须作为一个整体提交或回滚
- 如果事务中的任何元素失败,则整个事务将失败
一致性(Consistency)
- 当事务完成时,数据必须处于一致状态
- 在事务开始前,数据库中存储的数据处于一致状态
- 在正在进行的事务中,数据可能处于不一致的状态
- 当事务成功完成时,数据必须再次回到已知的一致状态
隔离性(Isolation)
- 对数据进行修改的所有并发事务是彼此隔离的,表明事务必须是独立的,它不应以任何方式依赖于或影响其他事务
- 修改数据的事务可在另一个使用相同数据的事务开始之前访问这些数据,或者在另一个使用相同数据的事务结束之后访问这些数据
持久性(Durability)
- 指不管系统是否发生故障,事务处理的结果都是永久的
- 一旦事务被提交,事务的效果会被永久地保留在数据库中
注意:
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
mysql> SET AUTOCOMMIT=0;
mysql>use auth;
mysql>CREATE TABLE kgc_transaction_test( id int(5)) engine=innodb;
mysql>select * from kgc_transaction_test;
mysql>begin; //开始事务
mysql>insert into kgc_transaction_test value(1);
mysql> insert into kgc_transaction_test value(2);
mysql> commit; //提交事务
mysql>select * from kgc_transaction_test;
mysql>begin; //开始事务
mysql>insert into kgc_transaction_test values(3);
mysql>rollback; //回滚
mysql> select * from kgc_transaction_test; //因为回滚所以数据没有插入