传送门:MySql使用手册–基础篇(联动大佬)
简而言之,存储引擎就是指表的类型,数据库的存储引擎决定了表在计算机中的存储方式。存储引擎的概念是MySql的特点,而且是一种插入式的存储引擎概念,这决定了MySQL数据库中的表可以用不同的方式存储,用户可以根据自己不同的要求,来选择不同的存储方式、是否进行事务处理等。
InnoDB是MySQL的默认事务引擎,也是最重要、使用最广泛的存储引擎。它被设计用来处理大量的短期事务,短期事务大部分情况是正常提交的,很少会被回滚(当事务中的某条语句出错是,整个事务并不会成功执行,而是会退回到事务中所有语句执行之前,这里先大概了解,后面会更新文章讲解回滚的机制以及实现原理)。
在MySql5.1及之前的版本,MyISAM是默认的存储引擎。MyISAM提供了大量的特性,包括全文索引、压缩、空间函数等,但是MyISAM不支持事务和行级锁,而且有一个毫无疑问的缺陷就是就是崩溃后无法安全恢复。
MyISAM会将表存储在两个文件中;数据文件和索引文件,分别以 .MYD 和 .MYI为扩展名。MyISAM表可以包含动态或者静态(长度固定)行。MySQL会根据表的定义来决定采用何种行格式。MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间,或者操作系统中单个文件的最大尺寸。
作为MySQl最早的存储引擎之一,MyISAM有一些已经开发出来很多年的特性,可以满足用户的实际需求。
如果表在创建并导入数据后,不会再进行修改操作,那么这样的表或许适合采用MyISAM压缩表。
可以使用myisampack对MyISAM表进行压缩。压缩表是不能进行修改的(除非先将表解除压缩,修改数据,再次压缩)。压缩表可以极大地减少磁盘空间占用,因此也可以减少磁盘I/O,从而提升查询性能。压缩表也支持索引,但索引也是只读的。
索引是一种特殊的数据库结构,可以用来快速查询数据库表中的特定记录,由表中的一列或者多列组合而成,创建在表上,是对数据库表中一列或者多列的值进行排序的一种结构,可以提高查询速度。
总的来说,其实可以把索引归为单列索引、多列索引、全文索引和空间索引四种。
一般来说,如果没有特别指明,那么多半说的是B-Tree索引。它使用B-Tree数据结构来存储数据。
B-Tree通常意味着所有的值都是按顺序存储,并且每一个叶子页到根的距离相同。下图便抽象表示了B-Tree的结构。
其中,根节点中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点。这些指针实际定义了子节点页中值的上下限,最终存储引擎要么是找到对应的值,要么不存在。
B-Tree索引的限制
哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个比较小的值,并且不同键值的行计算出来的哈希码也不一样,哈希索引将所有的哈希码储存在索引中,同时在哈希表中保存指向每个数据行的指针。
如果多列哈希值想相同,索引会以链表的方式放多个记录指针到同一个哈希目录中。
哈希索引的限制
**含义:**视图就是从一个或多个表中导出来的表,是一个虚拟存在的表,就像是一个窗口,通过这个窗口用户可以看到系统专门提供的数据。这样,可以使用户操作更加方便,还可以保障数据库系统的安全性。
作用:
触发器是由INSERT、UPDATE和DELETE等事件来触发某种特定操作,满足触发器的触发条件时,数据库就会执行触发器中定义的语句,可以保证某些操作之间的一致性。
例如,当学生表中增加一个学生信息,学生总数必须同时改变。可以在里创建一个触发器,每次增加一个学生的记录,就执行一次计算学生总数的操作。这样就可以保证每次增加学生记录后,学生总数与记录保持一致。触发器的执行语句可能有一个,也可能有多个。
mysql> CREATE TRIGGER dept_trig1 BEFORE INSERT ON test1 FOR EACH ROW
INSERT INTO trigger_time VALUES(NOW());
Query OK, 0 rows affected (0.36 sec)
插入一条语句,查看结果:
mysql> SELECT * FROM trigger_time;
Empty set (0.01 sec)
mysql> INSERT test1 VALUES(1,'ko','男');
Query OK, 1 row affected (1.88 sec)
mysql> SELECT * FROM trigger_time;
+-----------+
| exec_time |
+-----------+
| 21:46:33 |
+-----------+
1 row in set (0.00 sec)
mysql> DELIMITER &&
mysql> CREATE TRIGGER dept_trig2 AFTER DELETE
-> ON test1 FOR EACH ROW
-> BEGIN
-> INSERT trigger_time VALUES('21:55:01');
-> INSERT trigger_time VALUES('21:55:06');
-> END
-> &&
Query OK, 0 rows affected (0.25 sec)
mysql> DELIMITER ;
结果如下:
mysql> SELECT * FROM trigger_time;
+-----------+
| exec_time |
+-----------+
| 21:46:33 |
+-----------+
1 row in set (0.00 sec)
mysql> DELETE FROM test1 WHERE id=1;
Query OK, 1 row affected (1.93 sec)
mysql> SELECT * FROM trigger_time;
+-----------+
| exec_time |
+-----------+
| 21:46:33 |
| 21:55:01 |
| 21:55:06 |
+-----------+
3 rows in set (0.00 sec)
查看触发器
1.SHOW TRIGGERS语句
2.在trigeers表中查看触发器信息(详细信息)
也可以使用:SELECT * FROM information_schema.triggers WHERE TRIGGER_NAME=‘触发器名’;
mysql> SELECT * FROM information_schema.triggers\G;
*************************** 1. row ***************************
TRIGGER_CATALOG: def
TRIGGER_SCHEMA: sys
TRIGGER_NAME: sys_config_insert_set_user
EVENT_MANIPULATION: INSERT
EVENT_OBJECT_CATALOG: def
EVENT_OBJECT_SCHEMA: sys
EVENT_OBJECT_TABLE: sys_config
ACTION_ORDER: 1
ACTION_CONDITION: NULL
ACTION_STATEMENT: BEGIN IF @sys.ignore_sys_config_triggers != true AND NEW.set_by IS NULL THEN SET NEW.set_by = USER(); END IF; END
ACTION_ORIENTATION: ROW
ACTION_TIMING: BEFORE
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
ACTION_REFERENCE_OLD_ROW: OLD
ACTION_REFERENCE_NEW_ROW: NEW
CREATED: 2021-01-24 16:42:04.42
SQL_MODE:
DEFINER: mysql.sys@localhost
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
DATABASE_COLLATION: utf8_general_ci
*************************** 2. row ***************************
TRIGGER_CATALOG: def
TRIGGER_SCHEMA: sys
TRIGGER_NAME: sys_config_update_set_user
EVENT_MANIPULATION: UPDATE
EVENT_OBJECT_CATALOG: def
EVENT_OBJECT_SCHEMA: sys
EVENT_OBJECT_TABLE: sys_config
ACTION_ORDER: 1
ACTION_CONDITION: NULL
ACTION_STATEMENT: BEGIN IF @sys.ignore_sys_config_triggers != true AND NEW.set_by IS NULL THEN SET NEW.set_by = USER(); END IF; END
ACTION_ORIENTATION: ROW
ACTION_TIMING: BEFORE
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
ACTION_REFERENCE_OLD_ROW: OLD
ACTION_REFERENCE_NEW_ROW: NEW
CREATED: 2021-01-24 16:42:04.59
SQL_MODE:
DEFINER: mysql.sys@localhost
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
DATABASE_COLLATION: utf8_general_ci
*************************** 3. row ***************************
TRIGGER_CATALOG: def
TRIGGER_SCHEMA: test_db1
TRIGGER_NAME: dept_trig1
EVENT_MANIPULATION: INSERT
EVENT_OBJECT_CATALOG: def
EVENT_OBJECT_SCHEMA: test_db1
EVENT_OBJECT_TABLE: test1
ACTION_ORDER: 1
ACTION_CONDITION: NULL
ACTION_STATEMENT: INSERT INTO trigger_time VALUES(NOW())
ACTION_ORIENTATION: ROW
ACTION_TIMING: BEFORE
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
ACTION_REFERENCE_OLD_ROW: OLD
ACTION_REFERENCE_NEW_ROW: NEW
CREATED: 2021-03-13 21:43:50.31
SQL_MODE: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
DEFINER: root@localhost
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
DATABASE_COLLATION: latin1_swedish_ci
*************************** 4. row ***************************
TRIGGER_CATALOG: def
TRIGGER_SCHEMA: test_db1
TRIGGER_NAME: dept_trig2
EVENT_MANIPULATION: DELETE
EVENT_OBJECT_CATALOG: def
EVENT_OBJECT_SCHEMA: test_db1
EVENT_OBJECT_TABLE: test1
ACTION_ORDER: 1
ACTION_CONDITION: NULL
ACTION_STATEMENT: BEGIN
INSERT trigger_time VALUES('21:55:01');
INSERT trigger_time VALUES('21:55:06');
END
ACTION_ORIENTATION: ROW
ACTION_TIMING: AFTER
ACTION_REFERENCE_OLD_TABLE: NULL
ACTION_REFERENCE_NEW_TABLE: NULL
ACTION_REFERENCE_OLD_ROW: OLD
ACTION_REFERENCE_NEW_ROW: NEW
CREATED: 2021-03-13 21:54:36.17
SQL_MODE: STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
DEFINER: root@localhost
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
DATABASE_COLLATION: latin1_swedish_ci
4 rows in set (0.13 sec)
在MySQL中,触发器的执行顺序是BERORE触发器,表操作和AFTER触发器。
实例:
mysql> CREATE TRIGGER before_insert BEFORE INSERT
-> ON test1 FOR EACH ROW
-> INSERT INTO trigger_test VALUES(null,'before_insert');
Query OK, 0 rows affected (0.35 sec)
mysql> CREATE TRIGGER after_insert AFTER INSERT
-> ON test1 FOR EACH ROW
-> INSERT INTO trigger_test VALUES(null,'after_insert');
Query OK, 0 rows affected (0.45 sec)
结果:
mysql> SELECT * FROM trigger_test;
Empty set (0.00 sec)
mysql> INSERT test1 VALUES(1,'pl','男');
Query OK, 1 row affected (0.51 sec)
mysql> SELECT * FROM trigger_test;
+----+---------------+
| id | info |
+----+---------------+
| 2 | before_insert |
| 3 | after_insert |
+----+---------------+
2 rows in set (0.00 sec)
存储过程和函数是在数据库中定义一些SQL语句的集合,然后直接调用这些存储过程和函数来执行已经定义好的SQL语句,这样可以避免开发人员重复编写相同的SQL语句,并且,存储过程函数是在MySQL服务器中存储和执行的,可以减少客户端和服务端的数据传输。
存储过程:
CALL sp_name([parameter[…]]);
sp_name 为名称,paramter 为参数
存储函数: 这里与MySQL内部函数的使用方法是一样的,一个性质。
查询语句可能有多条记录,在存储过程和函数中使用光标来逐条读取查询中的记录。
语法:
创建:
DECLARE cursor_name CURSOR FOR select_statement;
第一个参数表示名称,第二个为SELECT语句
打开:
OPEN cursor_name;
使用:
FETCH cur_name INTO var_name…(多个)
这里var_name 必须在声明光标之前就定义好
关闭:
CLOSE cursor_name;
注意:
光标必须声明在处理程序之前,并且声明在变量和条件之后。
事务就是一组原子性的SQL查询,或者说一个独立的工作单元。也就是说事务内的语句,要么全部都执行成功,要么全都执行失败。
在MySQL中,如果事务中的一条语句执行失败,那么将会回滚到事务开始执行前的状态。不会对数据库产生影响。
ACID表示原子性(atomicity)、一致性(consistency)、隔离性(islation)和持久性(durability)。一个运行良好的事务处理系统给,必须具备这些标准特征。
死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能产生死锁。多个事务同时锁定同一个资源时也会产生死锁。这样说可能不太好理解,我们举个例子:
试想,上面两个事务同时处理表,假设,两个事务都执行了第一条UPDATE语句,更新了一行数据,同时也锁定了该行数据,这时,每个事务都尝试去执行第二条语句,却发现该行已被对方锁定,然后两个事务都等待对方释放锁,又同时持有对方的锁,则陷入死循环,除非由外部因素介入才可能解除死锁。
死锁的解决办法: 为了解决这种问题,数据库实现了各种死锁检测和死锁超时机制。越复杂的系统,比如InnoDB存储引擎,越能检测到思死锁的循环依赖,并立即返回一个错误。
还有一种解决方式是,查询的时间达到锁等待超时的设定后放弃请求,这种方式通常来说不太好。
InnoDB目前的处理死锁方式:将持有最少行级排他锁的事务进行回滚(这是相对比较简单的死锁回滚算法)。
死锁发生之后,只有部分或者完全回滚其中一个事务,才能打破死锁。对于事务型的系统,这是无法避免的,所以应用程序在设计时必须考虑如何处理死锁。大多数情况下只需要重新执行因死锁回滚的事务即可。
MySQL中提供了两种事务型的存储引擎:InnoDB和NDB Cluster。
自动提交(AUTOCOMMIT)
MySQL默认采用自动提交(AUTOCOMMIT)模式。
如果不是显式的开启一个事物,则每个查询都被当作一个事务执行提交操作。在当前连接中,可以通过设置AUTOCOMMIT变量来启动或者自动提交模式。
1或者ON表示启用,0或者OFF表示禁用。当为0时,所有查询在一个事务中,只有显式地执行COMMIT提交或者ROLLBACK回滚,该事务结束,同时又开始了另一个新事物。
修改AUTOCOMMIT对非事务型的表,比如MyISAM或者内存表,不会有任何影响,对这类表,没有COMMIT或者ROLLBACK的概念,也可以说相当于一直处于AUTOCONNIT启用的模式。
[1].MySQl5.6官方手册https://dev.mysql.com/doc/refman/5.6/en/preface.html
[2].黄缙华 《MySQL入门很简单》
[3].《高性能MySQL》第三版