MySQL 存储引擎和锁
===============================================================================
存储引擎:
1.介绍
★存储引擎:Storage Engine(负责向下管理文件,向上提供关系模型)
MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能;
表类型:表级别概念,不建议在同一个库中的表上使用不同的ENGINE;
★常见的存储引擎:
MyISAM, Aria, InnoDB, MRG_MYISAM, CSV, BLACKHOLE, MEMORY, PERFORMANCE_SCHEMA, ARCHIVE, FEDERATED
★查看数据库支持的存储引擎种类:
mysql> SHOW ENGINES;
★查看默认的存储引擎:
mysql> SHOW GLOBA|[SESSION] VARIABLES [LIKE clause];
★查看指定表的存储引擎:
mysql> SHOW TABLE STATUS LIKE clause;
★创建表时设定其存储引擎的方法:
CREATE TABLE ... ENGINE[=]STORAGE_ENGINE_NAME ...
演示:
1.查看mysql所支持的存储引擎;
MariaDB [mysql]> SHOW ENGINES;
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| CSV | YES | CSV storage engine | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| FEDERATED | YES | FederatedX pluggable storage engine | YES | NO | YES |
| Aria | YES | Crash-safe tables with MyISAM heritage | NO | NO | NO |
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
10 rows in set (0.00 sec)
2.查看默认的存储引擎;
MariaDB [mysql]> show global variables like '%storage_engine%';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine | InnoDB |
+------------------------+--------+
2 rows in set (0.01 sec)
3.查看指定表的存储引擎(即查看表的状态信息)
MariaDB [mysql]> SHOW TABLE STATUS LIKE 'user'\G
*************************** 1. row ***************************
Name: user
Engine: MyISAM
Version: 10
Row_format: Dynamic
Rows: 10
Avg_row_length: 102
Data_length: 1024
Max_data_length: 281474976710655
Index_length: 2048
Data_free: 0
Auto_increment: NULL
Create_time: 2016-10-12 20:06:15
Update_time: 2016-11-12 18:13:46
Check_time: NULL
Collation: utf8_bin
Checksum: NULL
Create_options:
Comment: Users and global privileges
1 row in set (0.00 sec)
InnoDB存储引擎
---Percona-XtraDB, Supports transactions(支持事务), row-level locking(行级锁), and foreign keys(外键)
★表结构的定义:
在数据库目录,tbl_name.frm
★数据存储于“表空间(table space)"中:
☉所有InnoDB表的数据和索引存储于同一个表空间中;
◆表空间文件:datadir定义的目录中
文件:ibdata1, ibdata2, ...
☉innodb_file_per_table=ON,意味着每表使用单独的表空间文件;
◆数据文件(数据和索引,存储于数据库目录): tbl_name.ibd
注意:
默认所有innodb存储引擎的数据和索引都存储于一个表空间中;
要想使每表使用单独的表空间文件,就要在/etc/my.cnf中定义
★功能:
☉事务型存储引擎
适合对事务要求较高的场景中,但较适用于处理大量短期事务;
☉基于MVCC(Mutli Version Concurrency Control)支持高并发;
支持四个隔离级别,默认级别为 REPEATABLE-READ;间隙锁以防止幻读;
☉使用聚集索引(主键索引);
☉支持"自适应Hash索引";
☉锁粒度:
行级锁;间隙锁;
★查看innodb的状态
SHOW ENGINE INNODB STATUS
演示:
1.查看mysql数据库目录
[root@centos7 ~]# cd /var/lib/mysql/
[root@centos7 mysql]# ll -h
total 29M
-rw-rw---- 1 mysql mysql 16K Nov 26 21:40 aria_log.00000001
-rw-rw---- 1 mysql mysql 52 Nov 26 21:40 aria_log_control
drwx------ 2 mysql mysql 4.0K Nov 25 19:16 hellodb
-rw-rw---- 1 mysql mysql 18M Nov 27 11:20 ibdata1 //innodb存储引擎的数据文件存放位置,即公共表空间文件
-rw-rw---- 1 mysql mysql 5.0M Nov 27 11:20 ib_logfile0 //事物日志相关的文件
-rw-rw---- 1 mysql mysql 5.0M Nov 27 11:20 ib_logfile1 //事物日志相关的文件
drwx------ 2 mysql mysql 4.0K Oct 12 20:06 mysql
srwxrwxrwx 1 mysql mysql 0 Nov 27 09:49 mysql.sock
drwx------ 2 mysql mysql 4.0K Oct 12 20:06 performance_schema
drwx------ 2 mysql mysql 131 Oct 20 16:55 Syslog
drwx------ 2 mysql mysql 79 Nov 24 19:37 testdb //创建的数据库目录
drwx------ 2 mysql mysql 36K Oct 13 10:22 ultrax
drwx------ 2 mysql mysql 12K Nov 12 21:47 zabbix
2.查看testdb数据库的文件,如下:
MariaDB [testdb]> show tables; //testdb数据库中有两张表,对应/var/lib/mysql目录下的testdb目录
+------------------+
| Tables_in_testdb |
+------------------+
| tbl1 |
| tbl2 |
+------------------+
2 rows in set (0.00 sec)
MariaDB [testdb]> show table status like 'tbl2'\G
*************************** 1. row ***************************
Name: tbl2
Engine: InnoDB //存储引擎
Version: 10
Row_format: Compact
Rows: 3
Avg_row_length: 5461
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2016-11-24 19:37:41
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
MariaDB [testdb]> desc tbl2; //查看表结构
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| id | int(10) unsigned | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
| age | tinyint(3) unsigned | YES | | NULL | |
| gender | enum('F','M') | YES | | NULL | |
+--------+---------------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
[root@centos7 mysql]# pwd
/var/lib/mysql
[root@centos7 mysql]# cd testdb/
[root@centos7 testdb]# ll
total 220
-rw-rw---- 1 mysql mysql 65 Nov 24 15:39 db.opt
-rw-rw---- 1 mysql mysql 8586 Nov 24 15:41 tbl1.frm //定义表格式(tbl、tbl2的格式)
-rw-rw---- 1 mysql mysql 98304 Nov 24 16:00 tbl1.ibd //数据存放位置,每表使用单独的表空间,不再使用默认的公共表空间 ibdata1
-rw-rw---- 1 mysql mysql 8654 Nov 24 19:37 tbl2.frm
-rw-rw---- 1 mysql mysql 98304 Nov 24 21:02 tbl2.ibd
3.innodb存储引擎的相关参数
MariaDB [testdb]> show variables like '%innodb%';
+-------------------------------------------+------------------------+
| Variable_name | Value |
+-------------------------------------------+------------------------+
| have_innodb | YES |
| ignore_builtin_innodb | OFF |
| innodb_adaptive_flushing | ON |
| innodb_adaptive_flushing_method | estimate |
| innodb_adaptive_hash_index | ON |
| innodb_adaptive_hash_index_partitions | 1 |
| innodb_additional_mem_pool_size | 8388608 |
| innodb_autoextend_increment | 8 |
| innodb_autoinc_lock_mode | 1 |
| innodb_blocking_buffer_pool_restore | OFF |
| innodb_buffer_pool_instances | 1 |
| innodb_buffer_pool_populate | OFF |
| innodb_buffer_pool_restore_at_startup | 0 |
| innodb_buffer_pool_shm_checksum | ON |
| innodb_buffer_pool_shm_key | 0 |
| innodb_buffer_pool_size | 134217728 |
| innodb_change_buffering | all |
| innodb_checkpoint_age_target | 0 |
| innodb_checksums | ON |
| innodb_commit_concurrency | 0 |
| innodb_concurrency_tickets | 500 |
| innodb_corrupt_table_action | assert |
| innodb_data_file_path | ibdata1:10M:autoextend |
| innodb_data_home_dir | |
| innodb_dict_size_limit | 0 |
| innodb_doublewrite | ON |
| innodb_doublewrite_file | |
| innodb_fake_changes | OFF |
| innodb_fast_checksum | OFF |
| innodb_fast_shutdown | 1 |
| innodb_file_format | Antelope |
| innodb_file_format_check | ON |
| innodb_file_format_max | Antelope |
| innodb_file_per_table | ON |
| innodb_flush_log_at_trx_commit | 1 |
| innodb_flush_method | |
| innodb_flush_neighbor_pages | area |
| innodb_force_load_corrupted | OFF |
| innodb_force_recovery | 0 |
| innodb_ibuf_accel_rate | 100 |
| innodb_ibuf_active_contract | 1 |
| innodb_ibuf_max_size | 67092480 |
| innodb_import_table_from_xtrabackup | 0 |
| innodb_io_capacity | 200 |
| innodb_kill_idle_transaction | 0 |
| innodb_large_prefix | OFF |
| innodb_lazy_drop_table | 0 |
| innodb_lock_wait_timeout | 50 |
| innodb_locking_fake_changes | ON |
| innodb_locks_unsafe_for_binlog | OFF |
| innodb_log_block_size | 512 |
| innodb_log_buffer_size | 8388608 |
| innodb_log_file_size | 5242880 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
| innodb_max_bitmap_file_size | 104857600 |
| innodb_max_changed_pages | 1000000 |
| innodb_max_dirty_pages_pct | 75 |
| innodb_max_purge_lag | 0 |
| innodb_merge_sort_block_size | 1048576 |
| innodb_mirrored_log_groups | 1 |
| innodb_old_blocks_pct | 37 |
| innodb_old_blocks_time | 0 |
| innodb_open_files | 300 |
| innodb_page_size | 16384 |
| innodb_print_all_deadlocks | OFF |
| innodb_purge_batch_size | 20 |
| innodb_purge_threads | 1 |
| innodb_random_read_ahead | OFF |
| innodb_read_ahead | linear |
| innodb_read_ahead_threshold | 56 |
| innodb_read_io_threads | 4 |
| innodb_recovery_stats | OFF |
| innodb_recovery_update_relay_log | OFF |
| innodb_replication_delay | 0 |
| innodb_rollback_on_timeout | OFF |
| innodb_rollback_segments | 128 |
| innodb_show_locks_held | 10 |
| innodb_show_verbose_locks | 0 |
| innodb_simulate_comp_failures | 0 |
| innodb_spin_wait_delay | 6 |
| innodb_stats_auto_update | 1 |
| innodb_stats_method | nulls_equal |
| innodb_stats_modified_counter | 0 |
| innodb_stats_on_metadata | ON |
| innodb_stats_sample_pages | 8 |
| innodb_stats_traditional | ON |
| innodb_stats_update_need_lock | 1 |
| innodb_strict_mode | OFF |
| innodb_support_xa | ON |
| innodb_sync_spin_loops | 30 |
| innodb_table_locks | ON |
| innodb_thread_concurrency | 0 |
| innodb_thread_concurrency_timer_based | OFF |
| innodb_thread_sleep_delay | 10000 |
| innodb_track_changed_pages | OFF |
| innodb_use_atomic_writes | OFF |
| innodb_use_fallocate | OFF |
| innodb_use_global_flush_log_at_trx_commit | ON |
| innodb_use_native_aio | ON |
| innodb_use_stacktrace | OFF |
| innodb_use_sys_malloc | ON |
| innodb_use_sys_stats_table | OFF |
| innodb_version | 5.5.43-MariaDB-37.2 |
| innodb_write_io_threads | 4 |
+-------------------------------------------+------------------------+
105 rows in set (0.00 sec)
-------------------------------------------------------------------------------
innodb总结:
★数据存储:表空间;
★并发:MVCC,间隙锁,行级锁;
★索引:聚集索引、辅助索引;
★性能:预读操作、内存数据缓冲、内存索引缓存、自适应Hash索引、插入操作缓存区;
★备份:支持热备;
MyISAM:存储引擎
★特性:
支持全文索引(FULLTEXT index)、压缩、空间函数(GIS);
不支持事务;
锁粒度:表级锁;
崩溃无法保证表安全恢复
★适用场景:
只读或读多写少的场景、较小的表(以保证崩溃后恢复的时间较短);
★文件:每个表有三个文件,存储于数据库目录中
tbl_name.frm:表格式定义;
tbl_name.MYD:数据文件;
tbl_name.MYI:索引文件;
总结:
加锁和并发:表级锁;
修复:手动或自动修复、但可能会丢失数据;
索引:非聚集索引;
延迟索引更新;
表压缩;
演示:
MariaDB [hellodb]> show table status like 'students'\G
*************************** 1. row ***************************
Name: students
Engine: MyISAM
Version: 10
Row_format: Dynamic
Rows: 25
Avg_row_length: 24
Data_length: 624
Max_data_length: 281474976710655
Index_length: 3072
Data_free: 0
Auto_increment: 26
Create_time: 2016-11-27 15:01:38
Update_time: 2016-11-27 15:01:38
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
[root@centos7 mysql]# cd hellodb/
[root@centos7 hellodb]# ll
total 140
-rw-rw---- 1 mysql mysql 8636 Nov 25 19:16 classes.frm # 每个表有三个文件
-rw-rw---- 1 mysql mysql 172 Nov 25 19:16 classes.MYD
-rw-rw---- 1 mysql mysql 2048 Nov 25 19:16 classes.MYI
-rw-rw---- 1 mysql mysql 8630 Nov 25 19:16 coc.frm
-rw-rw---- 1 mysql mysql 112 Nov 25 19:16 coc.MYD
-rw-rw---- 1 mysql mysql 2048 Nov 25 19:16 coc.MYI
-rw-rw---- 1 mysql mysql 8602 Nov 25 19:16 courses.frm
-rw-rw---- 1 mysql mysql 144 Nov 25 19:16 courses.MYD
-rw-rw---- 1 mysql mysql 2048 Nov 25 19:16 courses.MYI
-rw-rw---- 1 mysql mysql 61 Nov 25 19:16 db.opt
-rw-rw---- 1 mysql mysql 8658 Nov 25 19:16 scores.frm
-rw-rw---- 1 mysql mysql 180 Nov 25 19:16 scores.MYD
-rw-rw---- 1 mysql mysql 2048 Nov 25 19:16 scores.MYI
-rw-rw---- 1 mysql mysql 8736 Nov 27 15:01 students.frm
-rw-rw---- 1 mysql mysql 624 Nov 27 15:01 students.MYD
-rw-rw---- 1 mysql mysql 3072 Nov 27 15:01 students.MYI
-rw-rw---- 1 mysql mysql 8656 Nov 25 19:16 teachers.frm
-rw-rw---- 1 mysql mysql 92 Nov 25 19:16 teachers.MYD
-rw-rw---- 1 mysql mysql 2048 Nov 25 19:16 teachers.MYI
-rw-rw---- 1 mysql mysql 8622 Nov 25 19:16 toc.frm
-rw-rw---- 1 mysql mysql 0 Nov 25 19:16 toc.MYD
-rw-rw---- 1 mysql mysql 1024 Nov 25 19:16 toc.MYI
其他存储引擎
★其它的存储引擎:
CSV:将CSV文件(以逗号分隔字段的文本文件)作为MySQL表文件;
MRG_MYISAM:将多个MyISAM表合并成的虚拟表;
BLACKHOLE:类似于/dev/null,不真正存储数据;
MEMORY:内存存储引擎,支持hash索引,表级锁,常用于临时表;
FEDERATED: 用于访问其它远程MySQL服务器上表的存储引擎接口;
★MariaDB额外支持很多种存储引擎:
OQGraph、SphinxSE、TokuDB、Cassandra、CONNECT、SQUENCE、...
★搜索引擎:
lucene:Solr, Elasticsearch
sphinx
并发控制:锁
锁:Lock
★锁类型 :
读锁:共享锁,可被多个读操作共享;
写锁:排它锁,独占锁;
★锁粒度:
表锁:在表级别施加锁,并发性较低;
行锁:在行级别施加锁,并发性较高;
★锁策略:在锁粒度及数据安全性之间寻求一种平衡机制;
存储引擎:级别以及何时施加或释放锁由存储引擎自行决定;
MySQL Server:表级别,可自行决定,也允许显式请求;
★锁类别:
显式锁:用户手动请求的锁;
隐式锁:存储引擎自行根据需要施加的锁;
★显式锁的使用:
☉LOCK TABLES
LOCK TABLES tbl_name read|write, tbl_name read|write, ... //添加锁
UNLOCK TABLES //释放锁
☉FLUSH TABLES
强制把内存中表的相关数据同步到磁盘之后,再一次以施加指令的类型的锁之后打开
FLUSH TABLES tbl_name,... [WITH READ LOCK];
UNLOCK TABLES;
eg:
FLUSH TABLES WITH READ LOCK(表示把所有的表同步到磁盘上,然后再请求读锁)
☉SELECT cluase
锁定指定表中的行
[FOR UPDATE | LOCK IN SHARE MODE]
演示:
在node1会话中请求读锁,发现可以正常读数据,但不能写数据
MariaDB [testdb]> LOCK TABLES tbl2 READ; # 请求读锁
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> SELECT * FROM tbl2; # 可以正常查看数据
+------+------+------+--------+
| id | name | age | gender |
+------+------+------+--------+
| 1 | tom | 21 | NULL |
| 2 | tao | 15 | NULL |
| 3 | jing | 22 | NULL |
+------+------+------+--------+
3 rows in set (0.00 sec)
MariaDB [testdb]> INSERT INTO tbl2 VALUES (4,'LinghuChong'); # 但是不能执行写操作,因为写操作为写锁,是独占的
ERROR 1099 (HY000): Table 'tbl2' was locked with a READ lock and can't be updated
在node2会话中,可以正常请求读锁,但是不能请求写锁,因为写锁只能是独占的,要想执行写操作必须保证其他会话中释放了所有的锁
MariaDB [testdb]> LOCK TABLES tbl2 READ;
Query OK, 0 rows affected (0.01 sec)
MariaDB [testdb]> SELECT * FROM tbl2;
+------+------+------+--------+
| id | name | age | gender |
+------+------+------+--------+
| 1 | tom | 21 | NULL |
| 2 | tao | 15 | NULL |
| 3 | jing | 22 | NULL |
+------+------+------+--------+
3 rows in set (0.01 sec)
MariaDB [testdb]> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> LOCK TABLES tbl2 WRITE; # 请求写锁,发现被阻塞,因为写锁是独占的,必须使node1会话中释放了读锁之后才可以请求读锁;
# 在node1会话中释放读锁,再次请求写锁发现可以正常请求
MariaDB [testdb]> LOCK TABLES tbl2 WRITE;
Query OK, 0 rows affected (10.49 sec) # 阻塞时长10.49s
此时,因为node2上请求了写锁,所以node1会话中再请求读锁,是被阻塞的,因为写锁为排他锁,连接写锁时,其他的会话中的任何读写操作均阻塞;只有等node2会话中写操作执行完成后释放了写锁,node1会话才可以请求读锁
MariaDB [testdb]> LOCK TABLES tbl2 READ; # 请求读锁阻塞
# node2释放写锁后,请求读锁成功
MariaDB [testdb]> LOCK TABLES tbl2 READ;
Query OK, 0 rows affected (5.66 sec) # 阻塞时长5.66s
注意:
大多数情况下,mysql都可以自行维护锁机制,而不用去手动施加。