理解MySQL数据库不可缺少的知识(索引,事务存储引擎)!
Posted handsomeboy-东
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解MySQL数据库不可缺少的知识(索引,事务存储引擎)!相关的知识,希望对你有一定的参考价值。
一、索引
概述:索引时数据库管理系统中一个排序的数据结构,就如一本书前面的目录,以协助快速查询、更新数据库表中的数据
索引的作用
- 能够大大加快数据的查询速度,当表很大或要查询多个表时,甚至可以成千上万倍地提高查询速度
- 可以降低数据库的I/O(读写)成本,成本和排序成本
- 可以加快表与表之间的连接
- 通过唯一索引可以保证数据表中数据的唯一性
- 可大大减少分组和排序的时间
索引的缺点
- 索引需要额外的磁盘空间
- 插入和修改数据时需要更多的时间,因为索引也需要时间变动
索引的应用
- 表的主键、外键必须要索引,主键和索引值都具有唯一性,有助于查询,外键关联另一个表的主键,添加索引多表查询时可以快速定位
- 数据记录超过300行时要有索引,否则数据量太大,每次查询都要把表遍历一遍,会影响数据库的性能
- 经常与其他表进行连接的表,在连接字段上应该建立索引
- 唯一性差的字段不适合建立索引
- 更新太频繁的字段不适合建立索引
- 经常初见where判断子句中的字段,需要建立索引
- 索引应该建在选择性高的字段上,如果很少的字段拥有相同值,既有很多独特值,则选择性很高
- 索引应该建在小字段上,对于大的文本字段甚至超长字段,不要键索引
索引的分类
普通索引
最基本的索引类型,没有唯一性之类的限制
- 直接创建索引
create index 索引名 on 表名 (列名[length]);
####lengh是可选项,如果没有则表示整个列的值作为索引,可以指定使用列前的length值来创建索引,索引名最好为_insex结尾
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| whd |
+--------------------+
5 rows in set (0.00 sec)
mysql> use whd;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+---------------+
| Tables_in_whd |
+---------------+
| whd2 |
| whd3 |
| xuyichishi |
+---------------+
3 rows in set (0.00 sec)
mysql> select * from whd2;
+----+---------+-----------+---------+
| id | name | score_new | address |
+----+---------+-----------+---------+
| 1 | lisi | 99 | 上海 |
| 2 | zhansan | 50 | 杭州 |
| 3 | wangwu | 20 | 杭州 |
| 4 | xuyi | 40 | 南京 |
| 5 | hh | 50 | 湖北 |
+----+---------+-----------+---------+
5 rows in set (0.00 sec)
mysql> create index address_index on whd2(address);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table whd2\\G;
*************************** 1. row ***************************
Table: whd2
Create Table: CREATE TABLE "whd2" (
"id" int(11) NOT NULL,
"name" varchar(10) NOT NULL,
"score_new" varchar(3) DEFAULT NULL,
"address" varchar(40) DEFAULT NULL,
PRIMARY KEY ("id"),
KEY "address_index" ("address")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
- 修改表方式创建索引
alter table 表名 add index 索引名 (列名);
mysql> alter table whd2 add index name_index (name);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table whd2\\G;
*************************** 1. row ***************************
Table: whd2
Create Table: CREATE TABLE "whd2" (
"id" int(11) NOT NULL,
"name" varchar(10) NOT NULL,
"score_new" varchar(3) DEFAULT NULL,
"address" varchar(40) DEFAULT NULL,
PRIMARY KEY ("id"),
KEY "address_index" ("address"),
KEY "name_index" ("name") #查看添加结果
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
- 创建表的时候指定索引
create table 表名(字段1 数据类型,字段2 数据类型………… ,index 索引名 (列名));
mysql> alter table whd2 add index name_index (name);
ERROR 1061 (42000): Duplicate key name 'name_index'
mysql> create table test (id int not null,name varchar(20),index name_inxex (name));
Query OK, 0 rows affected (0.01 sec)
mysql> show create table test\\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE "test" (
"id" int(11) NOT NULL,
"name" varchar(20) DEFAULT NULL,
KEY "name_inxex" ("name")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
唯一性索引
与普通索引不同于唯一索引列的的每个值都唯一,唯一索引允许为空,但是如果用组合索引创建,则列值的组合必须唯一,添加唯一键将自动添加唯一索引
- 直接创建唯一索引
create unique index 索引名 on 表名 (列名);
mysql> create unique index whd_index on test(id);
Query OK, 0 rows affected, 1 warning (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> show create table test\\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE "test" (
"id" int(11) NOT NULL,
"name" varchar(20) DEFAULT NULL,
UNIQUE KEY "whd_index" ("id"),
KEY "name_inxex" ("name")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
- 创建表时指定唯一索引
mysql> create table test1 (id int not null,name varchar(20),address varchar(40),index address_index (address));
Query OK, 0 rows affected (0.00 sec)
mysql> show create table test1\\G
*************************** 1. row ***************************
Table: test1
Create Table: CREATE TABLE "test1" (
"id" int(11) NOT NULL,
"name" varchar(20) DEFAULT NULL,
"address" varchar(40) DEFAULT NULL,
KEY "address_index" ("address")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
- 修改表方式创建
alter table 表名 add unique 索引名 (列名);
mysql> alter table test1 add unique name_index (name);
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table test1\\G
*************************** 1. row ***************************
Table: test1
Create Table: CREATE TABLE "test1" (
"id" int(11) NOT NULL,
"name" varchar(20) DEFAULT NULL,
"address" varchar(40) DEFAULT NULL,
UNIQUE KEY "name_index" ("name"),
KEY "address_index" ("address")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
主键索引
是一种特殊的唯一索引,必须指定为primary key
- 创建表的时候指定
mysql> create table test2 (id int,name varchar(40),primary key(id));
Query OK, 0 rows affected (0.01 sec)
mysql> show create table test2\\G
*************************** 1. row ***************************
Table: test2
Create Table: CREATE TABLE "test2" (
"id" int(11) NOT NULL,
"name" varchar(40) DEFAULT NULL,
PRIMARY KEY ("id")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
- 修改表方式时指定
alter table 表名 on primary key (列名); #主要一个表中只能由一个主键
组合索引
可以在单列或多列上创建的索引
create table 表名 (字段名1 数据类型,字段民2 数据类型,字段名3 数据类型,index 索引名 (列名1,列名2,列名3));
mysql> create table test3 (id int not null,name varchar(40),age varchar(3),address varchar(20),index id_index (id,name,agge));
Query OK, 0 rows affected (0.00 sec)
mysql> show create table test3\\G
*************************** 1. row ***************************
Table: test3
Create Table: CREATE TABLE "test3" (
"id" int(11) NOT NULL,
"name" varchar(40) DEFAULT NULL,
"age" varchar(3) DEFAULT NULL,
"address" varchar(20) DEFAULT NULL,
KEY "id_index" ("id","name","age")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
全文索引
适合在进行模糊查询的时候使用,可用于在一片文章中检索文本信息
- 创建表时指定索引
create table 表名 (字段1 数据类型,字段2 数据类型[,……],fulltext 索引名 (列名));
- 直接创建索引
create fulltext index 索引名 on 表名(列名):
- 修改表方式创建
alter table 表名 add fulltext 索引名 (列名);
- 使用全文索引查询
select * from 表名 where match(列名) against('查询内容');
查看索引
show index from 表名;
show index from 表名\\G;
show keys from 表名;
show keys from 表名\\G:
mysql> show index from test;
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test | 0 | test_index | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| test | 0 | id_index | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| test | 0 | whd_index | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| test | 1 | name_inxex | 1 | name | A | 0 | NULL | NULL | YES | BTREE | | |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)
删除索引
drop index 索引名 on 表名; #直接修改索引
alter table 表名 drop index 索引名; #就该方式删除索引
alter table 表名 drop primary key; #删除主键索引
mysql> show create table test\\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE "test" (
"id" int(11) NOT NULL,
"name" varchar(20) DEFAULT NULL,
UNIQUE KEY "test_index" ("id"),
UNIQUE KEY "id_index" ("id"),
UNIQUE KEY "whd_index" ("id"),
KEY "name_inxex" ("name")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> alter table test drop index whd_index;
Query OK, 0 rows affected (0.01 sec)
mysql> drop index test_index on test;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table test\\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE "test" (
"id" int(11) NOT NULL,
"name" varchar(20) DEFAULT NULL,
UNIQUE KEY "id_index" ("id"),
KEY "name_inxex" ("name")
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> update whd set money= money +200 where name='tianyi';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from whd;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | tianyi | 300 |
| 2 | dier | 100 |
+----+--------+-------+
2 rows in set (0.00 sec)
二、事务
事务是一个操作序列,这些操作要么执行,要么不执行,它是一个不可分割的工作单位,在数据库系统上执行并发操作时,事务是最小的控制单元,事务适用于多用户同时操作数据库的场景,如:银行,保险公司等
事务的ACID特点
- 原子性:指事务是一个不可再分割的工作单位,要么执行,要么不执行
- 一致性:表示事务开始之前和事务结束以后,数据库的完整性约束没有被破坏
- 隔离性:表示在并发环境中,当不同的事务处理相同的数据时,每个事务都有自己的完整数据空间
- 持久性:表示在事务完成后,该事务所对数据库所作的更改将持久的保存在数据库中,并不会被删除
数据不一致产生的结果
- 脏读(读取未提交的数据):表示读取了别的事务回滚前的脏数据,也就是说读取了一个事务想修改却在事务提交之前回滚而未修改成功的事务
- 不可重复读(前后多次读取的数据内容不一致),表示一个事务内的两个相同的查询却返回了不同的结果,如:事务A查询一个数据,事务B又对该数据进行了修改,事务A再查询该数据是修改后的结果
- 幻读(前后多次读取,数据的总量不一致):如:一个事务修改了表中的全部行数据行,而另一个事务又插入了一行数据,这就导致前一个事务的修改过后发现还有为被修改的行,如发现幻觉
- 丢失更新:两个事务同时修改一条数据,而后面修改的不知道前面事务的修改,所有会导致前面事务的修改记录被后面事务的修改而覆盖
MySQL事务隔离级别
- 1、read uncommitted :读取尚未提交的数据,不解决脏读
- 2、read conmmitted :读取已提交的数据,可以解决脏读
- 3、repeatable read :重复读取,可以解决脏读和不可重复读,这是mysql默认的隔离级别
- 4、serializable :串行化,可以解决脏读,不可重复读,和虚读(相当于锁表)
set global transaction isolation level read committed;
#设置全局事务隔离级别
show global variable like '%isolation%';
select @@session.tx_isolation;
#查询全局隔离级别
set session tansaction isolation level read committed;
#设置会话事务隔离级别
show session variable like ’%isolation%‘
select @@tx_isolation;
事务控制语句
- begin 或 start transaction :显示地开启一个事务
- commit 或 commit work :提交事务,并使已对数据库进行的所有修改变为永久性的
- rollback 或 rollback work :回滚会结束用户的事务,并撤销正在进行的所有未提交的修改
- savepoint 回滚点名称 :允许在事务中创建一个回滚点,一个事务中可以有多个savepoint
- rollback to [savepoint] 回滚点名称 :把事务回滚到标记点
(1)新建表,添加数据,测试提交事务
mysql> create table whd (id int(10) primary key not null,name varchar(40),money double);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into whd values(1,'tianyi',100);
mysql> insert into whd values(2,'dier',100);
Query OK, 1 row affected (0.00 sec)
mysql> begin; #表示事务的开始
Query OK, 0 rows affected (0.00 sec)
mysql> update whd set money= money +100 where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
- 再新开一个终端,进入数据库,查看whd表单的内容
mysql> select * from whd;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | tianyi | 300 |
| 2 | dier | 100 | #此时数据还未变化
+----+--------+-------+
2 rows in set (0.00 sec)
- 再提交事务然后查询
mysql> select * from whd;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | tianyi | 300 |
| 2 | dier | 200 |
+----+--------+-------+
- 测试回滚
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update whd set money= money -100 where id=2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from whd;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | tianyi | 300 |
| 2 | dier | 200 |
+----+--------+-------+
2 rows in set (0.00 sec)
mysql> rollback; #回滚到事务原点,并推出事务
Query OK, 0 rows affected (0.00 sec)
mysql> select * from whd;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | tianyi | 300 |
| 2 | dier | 200 | #查询结果
+----+--------+-------+
2 rows in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update whd set money= money -100 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> savepoint a; #打上标签a
Query OK, 0 rows affected (0.00 sec)
mysql> update whd set money= money +600 where id=2mysql 知识2