前面入门之后,下面继续进阶
链接:https://pan.baidu.com/s/18KDKZxnhmWH9Ebpdhy6DlA 提取码:7665
上面网盘地址自行取图“Mysql进阶思维导图.png”;下面是markdown转换后的格式
总结
这里是基于MySQL 5.7.28 安装目录的大致介绍,非DBA可以不用太详细去了解,有兴趣的可以自行去了解;其中/data、/log、/mysql。socket目录及文件是在安装是自行进行配置的;可以修改
加载顺序
读取路径修改
部分相关配置参数
首先需要了解选项组是什么,选项组就是my.cnf配置中用[]括起来的,譬如[client]、[mysqld]、[mysqld_safe]、……;这里只介绍部分;每个选项组对应的优先级可能不同,具体的自行百度吧
[client]
[client]
host=127.0.0.1
user=root
password=[yourpass]
#为了省去每次链接数据库都输入主机地址,用户,密码可以配置上面三个参数如果你的MYSQL用户名和UNIX的登陆名相同,可以不写user行
port = 3307 #默认连接端口
socket = /data/mysqldata/3307/mysql.sock #用于本地连接的socket套接字
default-character-set = utf8mb4 #编码
[mysqld]
[mysqld]
default-storage-engine=InnoDB #默认存储引擎INNODB
group_concat_max_len =99999 #GROUP_CONCAT长度
port = 3306 #端口号
socket = /usr/local/mysql/mysql.sock #套接字文件这里要注意:有时候重启mysql会提示/tmp/mysql.sock不存在
pid-file = /usr/local/mysql/mysqld.pid #pid写入文件位置
datadir = /home/data/mysql/data #数据库文件位置
open_files_limit = 10240 #控制文件打开的个数
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES #SQL模式,允许一些非法操作;相关参数值含义如下
#ONLY_FULL_GROUP_BY:对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么将认为这个SQL是不合法的,因为列不在GROUP BY从句中
#STRICT_TRANS_TABLES:在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做任何限制
#NO_ZERO_IN_DATE:在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入'0000-00-00'。在非严格模式,可以接受该日期,但会生成警告。
#NO_ZERO_DATE:在严格模式,不要将 '0000-00-00'做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告
#ERROR_FOR_DIVISION_BY_ZERO:在严格模式,在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时MySQL返回NULL。如果用到INSERT IGNORE或UPDATE IGNORE中,MySQL生成被零除警告,但操作结果为NULL。
#NO_AUTO_CREATE_USER:防止GRANT自动创建新用户,除非还指定了密码。
#NO_ENGINE_SUBSTITUTION:如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常。
skip-external-locking
#当外部锁定(external-locking)起作用时,每个进程若要访问数据表,
#则必须等待之前的进程完成操作并解除锁定。由于服务器访问数据表时经常需要等待解锁,
#因此在单服务器环境下external locking会让MySQL性能下降。
#所以在很多Linux发行版的源中,MySQL配置文件中默认使用了skip-external-locking来避免external locking。
skip-name-resolve #跳过DNS反向解析
explicit_defaults_for_timestamp #关闭TIMESTAMP类型默认值
skip-character-set-client-handshake #不受client字符集影响,保证sever端字符集
init-connect='SET NAMES utf8' #初始连接字符集UTF8
character-set-server=utf8 #默认数据库字符集
query_cache_type = 1 #查询缓存0,1,2,分别代表了off、on、demand
connect_timeout = 20 #单位秒,握手时间超过connect_timeout,连接请求将会被拒绝
slave_net_timeout = 30
#设置在多少秒没收到主库传来的Binary Logs events之后,从库认为网络超时,Slave IO线程会重新连接主库。
#该参数的默认值是3600s ,然而时间太久会造成数据库延迟或者主备库直接的链接异常不能及时发现。
#将 slave_net_timeout 设得很短会造成 Master 没有数据更新时频繁重连。一般线上设置为5s
log-slave-updates=1
#这个参数用来配置从服务器的更新是否写入二进制日志,这个选项默认是不打开的,
#但是,如果这个从服务器B是服务器A的从服务器,同时还作为服务器C的主服务器,那么就需要开发这个选项,
#这样它的从服务器C才能获得它的二进制日志进行同步操作
replicate-same-server-id=0 #用于slave服务器,io线程会把server id与自己相同的event写入日志,与log-slave-updates选项冲突
server_id=10112879101 #作为MASTER主服务器
log-bin =/home/data/mysql/binlog/mysql-bin.log #打开二进制日志功能.
#在复制(replication)配置中,作为MASTER主服务器必须打开此项
#如果你需要从你最后的备份中做基于时间点的恢复,你也同样需要二进制日志
relay-log=mysql-relay-bin #relay-log日志
master-info-repository=TABLE #master-info-repository打开以启用崩溃安全的二进制日志(在事务表而不是平面文件中存储信息)
relay-log-info-repository=TABLE #relay-log-info-repository打开以启用崩溃安全的从服务器功能(在事务表而不是平面文件中存储信息)
binlog-ignore-db=mysql # No sync databases
binlog-ignore-db=test # No sync databases
binlog-ignore-db=information_schema # No sync databases
binlog-ignore-db=performance_schema # No sync databases
#不写入binlog二进制日志中的数据库
binlog-do-db=business_db
binlog-do-db=user_db
binlog-do-db=plocc_system
#写入binlog二进制日志中数据库
expire-logs-days=15
max_binlog_size = 1073741824 # Bin logs size ( 1G )
#清理binlog
sync_binlog = 1000 #使binlog在每1000次binlog写入后与硬盘同步
replicate-do-db=business_db
replicate-do-db=user_db
replicate-do-db=plocc_system
#指定只复制哪个库的数据
event_scheduler=1 #开启事件调度器Event Scheduler
back_log = 500
#MySQL能暂存的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用。
#如果MySQL的连接数据达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,
#该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源
#如果系统在短时间内有很多连接,则需要增大该参数的值,该参数值指定到来的TCP/IP连接的监听队列的大小。默认值50。
max_connections = 6000 #MySQL允许最大的进程连接数,如果经常出现Too Many Connections的错误提示,则需要增大此值。
max_user_connection = 3000 #每个用户的最大的进程连接数
max_connect_errors = 6000
#每个客户端连接请求异常中断的最大次数,如果达到了此限制.
#这个客户端将会被MySQL服务阻止,直到执行了”FLUSH HOSTS” 或者服务重启
#非法的密码以及其他在链接时的错误会增加此值.
#查看 “Aborted_connects” 状态来获取全局计数器
table_cache = 614
#表调整缓冲区大小。
#table_cache 参数设置表高速缓存的数目。每个连接进来,都会至少打开一个表缓存。
#因此,table_cache 的大小应与 max_connections 的设置有关。例如,对于 200 个并行运行的连接,应该让表的缓存至少有 200 × N ,这里 N 是应用可以执行的查询的一个联接中表的最大数量。此外,还需要为临时表和文件保留一些额外的文件描述符。
#当Mysql访问一个表时,如果该表在缓存中已经被打开,则可以直接访问缓存;如果还没有被缓存但是在 Mysql 表缓冲区中还有空间,那么这个表就被打开并放入表缓冲区;如果表缓存满了,则会按照一定的规则将当前未用的表释放,或者临时扩大表缓存来存放,使用表缓存的好处是可以更快速地访问表中的内容。
#执行 flush tables 会清空缓存的内容。
#一般来说,可以通过查看数据库运行峰值时间的状态值 Open_tables 和 Opened_tables ,判断是否需要增加 table_cache 的值(其中 open_tables 是当前打开的表的数量, Opened_tables 则是已经打开的表的数量)。
#即如果open_tables接近table_cache的时候,并且Opened_tables这个值在逐步增加,那就要考虑增加这个#值的大小了。还有就是Table_locks_waited比较高的时候,也需要增加table_cache。
table_open_cache = 2048 #表描述符缓存大小,可减少文件打开/关闭次数
max_allowed_packet = 64M #设置在网络传输中一次消息传输量的最大值。系统默认值 为1MB,最大值是1GB,必须设置1024的倍数。当与大的BLOB字段一起工作时相当必要
binlog_cache_size = 1M
# 在一个事务中binlog为了记录SQL状态所持有的cache大小
# 如果你经常使用大的,多声明的事务,你可以增加此值来获取更大的性能.
# 所有从事务来的状态都将被缓冲在binlog缓冲中然后在提交后一次性写入到binlog中
# 如果事务比此值大, 会使用磁盘上的临时文件来替代.
# 此缓冲在每个连接的事务第一次更新状态时被创建
max_heap_table_size = 256M #独立的内存表所允许的最大容量.此选项为了防止意外创建一个超大的内存表导致用尽所有的内存资源
sort_buffer_size = 8M
#Sort_Buffer_Size被用来处理类似ORDER BY以及GROUP BY队列所引起的排序,每一个要做排序的请求,都会分到一个sort_buffer_size大的缓存
#Sort_Buffer_Size 是一个connection级参数,在每个connection(session)第一次需要使用这个buffer的时候,一次性分配设置的内存。
#Sort_Buffer_Size 并不是越大越好,由于是connection级的参数,过大的设置+高并发可能会耗尽系统内存资源。例如:500个连接将会消耗 500*sort_buffer_size(8M)=4G内存
#如果超过Sort_Buffer_Size设置的大小,MySQL会将数据写入磁盘来完成排序,导致效率降低。
#属重点优化参数
join_buffer_size = 8M
#用于表间关联缓存的大小,和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。
#大部分表关联都比较影响查询性能,
#所以将此值设大能够减轻性能影响。
#通过 “Select_full_join” 状态变量查看表关联的数量
thread_cache_size = 128
#thread_cache_size表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,
#如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,减少线程创建的开销
#可以通过比较 Connections 和 Threads_created 状态变量,来查看thread_cache_size的设置是否起作用。
#设置规则:1GB 内存配置为8,2GB配置为16,3GB配置为32,4GB或更高内存,可配置更大。
thread_concurrency = 8
#此值表示允许应用程序在同一时间运行的线程的数量.
#设置thread_concurrency的值的正确与否,对mysql的性能影响很大, 在多个cpu(或多核)的情况下,错误设置了thread_concurrency的值, 会导致mysql不能充分利用多cpu(或多核), 出现同一时刻只能一个cpu(或核)在工作的情况。
#thread_concurrency应设为CPU核数的2倍
#属重点优化参数
query_cache_size = 64M
#此值用来缓冲 SELECT 的结果并且在下一次同样查询的时候不再执行直接返回结果,如果你有大量的相同的查询并且很少修改表,那么query_cache_size可以极大的提高数据库性能,
#需要注意的是:有时候数据库出现了性能问题,大家就习惯的认为把这个值调大就行了。然而,这个参数加大后也引发了一系列问题。
#我们首先分析一下 query_cache_size的工作原理:一个SELECT查询在DB中工作后,DB会把该语句缓存下来,当同样的一个SQL再次来到DB里调用时,DB在该表没发生变化的情况下把结果从缓存中返回给Client。
#这里有一个关建点,就是DB在利用Query_cache工作时,要求该语句涉及的表在这段时间内没有发生变更。那如果该表在发生变更时,Query_cache里的数据又怎么处理呢?
#首先要把Query_cache和该表相关的语句全部置为失效,然后在写入更新。那么如果Query_cache非常大,该表的查询结构又比较多,查询语句失效也慢,一个更新或是Insert就会很慢,这样看到的就是Update或是Insert怎么这么慢了。
#所以在数据库写入量或是更新量也比较大的系统,该参数不适合分配过大。而且在高并发,写入量大的系统,建议把该功能禁掉。
#重点优化参数
query_cache_limit = 2M
#指定单个查询能够使用的缓冲区大小,只有小于此设定值的结果才会被缓冲
#此设置用来保护查询缓冲,防止极大的结果集将其他所有的查询结果都覆盖
#缺省为1M
ft_min_word_len = 4
#被全文检索索引的最小的字长.
#你也许希望减少它,如果你需要搜索更短字的时候.
#注意在你修改此值之后,
#你需要重建你的 FULLTEXT 索引
thread_stack = 192K
#设置MYSQL线程使用的堆大小,此容量的内存在每次连接时被预留.
#MySQL 本身常不会需要超过64K的内存
#如果你使用你自己的需要大量堆的UDF函数
#或者你的操作系统对于某些操作需要更多的堆,
#你也许需要将其设置的更高一点.
transaction_isolation = READ-COMMITTED
#设定默认的事务隔离级别.可用的级别如下:
#READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE
tmp_table_size = 256M
#此值表示内存中临时表的最大大小,超过限值后就往硬盘写
#此限制是针对单个表的,而不是总和
#注意:
#1. max_heap_table_size 比 tmp_table_size 小时,则系统会把 max_heap_table_size 的值作为最大的内存临时表的上限。这样可达到提高联接查询速度的效果,建议尽量优化查询,要确保查询过程中生成的临时表在内存中,避免临时表过大导致生成基于硬盘的MyISAM表。
#2. 通过show global status like '%created_tmp%' 查询:Created_tmp_disk_tables和Created_tmp_tables的值,Created_tmp_disk_tables / Created_tmp_tables 值越小越好
binlog_format=mixed #binlog日志类型;mixed:混合型
slow_query_log #开启慢查询日志
log_output = FILE #文件格式
long_query_time = 0.5
#所有的使用了比这个时间(以秒为单位)更多的查询会被认为是慢速查询.
#不要在这里使用”0″, 否则会导致所有的查询,甚至非常快的查询页被记录下来(由于MySQL 目前时间的精确度只能达到秒的级别).
slow_query_log_file=/usr/local/mysql/mysqld_slow.log #慢查询日志位置
总结
mysql的优化其实也主要是对配置文件中参数的优化,具体以实际情况而定;还有其他一些选项组的配置这块就不做阐述了,非DBA能了解这么多足以
id
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序。三种情况:
select_type
查询类型,主要用于区别普通查询、联合查询、子查询等的复杂查询。常见类型又六种
table
显示这一行的数据是关于哪张表
partitions
记录将与查询匹配的分区。对于非分区表,该值为NULL。
type
访问类型排列,共有八种类型(还有一个NULL)
possible_keys
显示可能应用在这张表中的索引,一个或多个。查询设计到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。
key
实际使用的索引。如果为NULL,则没有使用索引;查询中若使用了覆盖索引(覆盖索引:指查询的字段个数及顺序刚好与复合索引一致),则该索引仅出现在key列表中。
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引长度。在不损失精确性的情况下,长度越短越好。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
ref
显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
rows
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。
filtered
指示将按表条件筛选的表行的估计百分比。
最大值为100,这意味着不会对行进行过滤。
值从100开始减少表示过滤量增加。
Extra
包含不适合在其他列中显示但十分重要的额外信息。
-- 学生表students表结构如下:
CREATE TABLE `students` (
`no` int NOT NULL AUTO_INCREMENT COMMENT '学号',
`age` int NOT NULL DEFAULT '0' COMMENT '年龄',
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '姓名',
PRIMARY KEY (`no`),
KEY `idx_age` (`age`)
) ENGINE=InnoDB/MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='学生信息表';
-- 初始化学生表数据
INSERT INTO `students`(`no`, `age`, `name`) VALUES (1, 20, '张三');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (2, 23, '李四');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (3, 25, '王五');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (4, 32, '高六');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (5, 25, '刘七');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (6, 27, '朱八');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (7, 28, '陈七');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (8, 21, '赫赫');
INSERT INTO `students`(`no`, `age`, `name`) VALUES (9, 22, '一一');
MyISAM 索引实现
MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。
InnoDB索引实现
InnoDB引擎同样使用B+Tree作为索引结构,实现方式却完全不同。InnoDB表数据文件本身就是一个索引结构。
总结:MyISAM索引与InnoDB索引的区别
两者都不是指单独的索引类型,而是指的索引数据的存储方式的不同
聚簇索引
非聚簇索引
回表
先通过辅助索引找到数据的主键,在根据主键扫描主键索引找出对应的数据内容,这个时候就会多扫描一次索引,这个就叫做回表
覆盖索引
查询的列从索引中就能获得,不必去回表或者从数据区域找出数据,通俗的讲就是查询的列就是索引;这就是覆盖索引
最左匹配
对于复合索引,B+ Tree是按照从左到右进行匹配的;select中查询的索引条件不是按照索引从左到右顺序,依旧能使用到索引是因为mysql的优化器对sql进行了优化
索引下推
英文描述:Index Condition Pushdown;简称ICP。Mysql5.6的版本上推出,用于优化查询。
没有索引下推执行过程:
首先会忽略age条件,直接通过name进行查询,在(name,age)这课索引树上查找到了两个结果id分别为2,1,根据两个结果的id分别去查询主键索引树,最后查出结果,这里就会回表两次
索引下推执行过程:
不会忽略age条件,而是在索引内部就判断了age是否等于20,对于不等于20的记录直接跳过,因此在(name,age)这棵索引树中只匹配到了一个记录,此时拿着这个id去主键索引树中回表查询全部数据,这个过程只需要回表一次。
全值匹配
匹配最左前缀
匹配列前缀
匹配范围值
精确匹配某一列并范围匹配另外一列
只访问索引的查询
--创建数据表
source citydemo.sql;
--查找最常见的城市列表,发现每个值都出现89-141次,
select count(*) as cnt,city from citydemo group by city order by cnt desc limit 10;
--查找最频繁出现的城市前缀,先从8个前缀字母开始,发现比原来出现的次数更多,可以分别截取多个字符查看城市出现的次数
select count(*) as cnt,left(city,8) as pref from citydemo group by pref order by cnt desc limit 10;
select count(*) as cnt,left(city,14) as pref from citydemo group by pref order by cnt desc limit 10;
--此时前缀的选择性接近于完整列的选择性
--还可以通过另外一种方式来计算完整列的选择性,可以看到当前缀长度到达14之后,再增加前缀长度,选择性提升的幅度已经很小了
select count(distinct left(city,8))/count(*) as sel8,
count(distinct left(city,9))/count(*) as sel9,
count(distinct left(city,10))/count(*) as sel10,
count(distinct left(city,11))/count(*) as sel11,
count(distinct left(city,12))/count(*) as sel12,
count(distinct left(city,13))/count(*) as sel13,
count(distinct left(city,14))/count(*) as sel14,
count(distinct left(city,15))/count(*) as sel15,
count(distinct left(city,16))/count(*) as sel16
from citydemo;
--计算完成之后可以创建前缀索引
alter table citydemo add key(city(14));
--注意:前缀索引是一种能使索引更小更快的有效方法,但是也包含缺点:mysql无法使用前缀索引做order by 和 group by。
-- 执行数据导入
source rental.sql;
--sakila数据库中rental表在rental_date,inventory_id,customer_id上有rental_date的索引
--使用rental_date索引为下面的查询做排序
explain select rental_id,staff_id from rental where rental_date='2005-05-25' order by inventory_id,customer_id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rental
partitions: NULL
type: ref
possible_keys: rental_date
key: rental_date
key_len: 5
ref: const
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
--order by子句不满足索引的最左前缀的要求,也可以用于查询排序,这是因为所以你的第一列被指定为一个常数
--该查询为索引的第一列提供了常量条件,而使用第二列进行排序,将两个列组合在一起,就形成了索引的最左前缀
explain select rental_id,staff_id from rental where rental_date='2005-05-25' order by inventory_id desc\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rental
partitions: NULL
type: ref
possible_keys: rental_date
key: rental_date
key_len: 5
ref: const
rows: 1
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
--下面的查询不会利用索引
explain select rental_id,staff_id from rental where rental_date>'2005-05-25' order by rental_date,inventory_id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rental
partitions: NULL
type: ALL
possible_keys: rental_date
key: NULL
key_len: NULL
ref: NULL
rows: 16005
filtered: 50.00
Extra: Using where; Using filesort
--该查询使用了两中不同的排序方向,但是索引列都是正序排序的
explain select rental_id,staff_id from rental where rental_date>'2005-05-25' order by inventory_id desc,customer_id asc\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rental
partitions: NULL
type: ALL
possible_keys: rental_date
key: NULL
key_len: NULL
ref: NULL
rows: 16005
filtered: 50.00
Extra: Using where; Using filesort
1 row in set, 1 warning (0.00 sec)
--该查询中引用了一个不再索引中的列
explain select rental_id,staff_id from rental where rental_date>'2005-05-25' order by inventory_id,staff_id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rental
partitions: NULL
type: ALL
possible_keys: rental_date
key: NULL
key_len: NULL
ref: NULL
rows: 16005
filtered: 50.00
Extra: Using where; Using filesort
1 row in set, 1 warning (0.00 sec)
explain select * from user where phone=13800001234; #不会触发索引
explain select * from user where phone='13800001234'; #触发索引
show profiles用来查询SQL执行时间,它是mysql 5.0.37之后添加的功能;select version();可查看MySQL版本。
1,查看show profiles功能是否开启,值为ON是开启,OFF是关闭
mysql > show variables like 'profiling';
2,开启show profiles功能
mysql > set profiling=1;
3,查看每条执行过的SQL语句的执行时间
mysql > show profiles;
4,查看一条SQL语句的详细执行时间
mysql > show profile for query ;
1.查看慢查询相关参数
mysql > show variables like 'slow_query%';
mysql > show variables like 'long_query_time';
2.设置方法
mysql> set global slow_query_log='ON';
设置慢查询日志存放的位置
mysql> set global slow_query_log_file='/local/mysql-5.7.28/data/slow.log';
查询超过2秒就记录
mysql> set global long_query_time=2;
方法二:配置文件设置修改配置文件my.cnf,在[mysqld]下的下方加入
[mysqld]
slow_query_log=ON
slow_query_log_file=/local/mysql-5.7.28/data/slow.log
long_query_time=2
3.重启MySQL服务
service mysqld restart
4.查看设置后的参数
mysql > show variables like 'slow_query%';
mysql > show variables like 'long_query_time';
5.测试
mysql> select sleep(3);
查看是否生成慢查询日志
cat /local/mysql-5.7.28/data/slow.log
mysql> show status like 'Handler_read%';
原子性(Atomicity)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)
更新丢失(Lost update)
时间 | 取款事务A | 转账事务B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询账户余额1000元 | |
T4 | 查询账户余额1000元 | |
T5 | 汇入100元修改金额为1100元 | |
T6 | 提交事务 | |
T7 | 取出100元将余额修改为900元 | |
T8 | 撤销事务 | |
T9 | 余额恢复为1000元(丢失更新) |
时间 | 取款事务A | 转账事务B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询账户余额1000元 | |
T4 | 查询账户余额1000元 | |
T5 | 取出100元将余额修改为900元 | |
T6 | 提交事务 | |
T7 | 汇入100元将余额修改为1100元 | |
T8 | 提交事务 | |
T9 | 查询账户余额1100元(丢失更新) |
脏读(Dirty Read)
不可重复读(Non-repeatable Read)
虚读(幻读Phantom-Read)
为了达到事务的四大特性;解决事务并发引起的问题
READ-UNCOMMITTED(读取未提交)
READ-COMMITTED(读取已提交)
REPEATABLE-READ(可重复读)
SERIALIZABLE(可串行化)
这里需要注意的是:MySQL默认的隔离级别为REPEATABLE-READ,并且是严格遵循数据库规范设计的,即支持4种隔离级别;Oracle默认的隔离级别为Read committed,并且不支持这4种隔离级别,只支持这4种隔离级别中的2种,Read committed和Serializable。
事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下一般会用到 SERIALIZABLE(可串行化) 隔离级别。
Serializable隔离级别,虽然可避免所有问题,但性能、效率是最低的,原因是它采取的是锁表的方式,即单线程的方式,即有一个事务来操作这个表了,另外一个事务只能等在外面进不来。
1、悲观锁
悲观锁,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统的数据访问层中实现了加锁机制,也无法保证外部系统不会修改数据。
2、乐观锁
乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以只会在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回用户错误的信息,让用户决定如何去做。实现乐观锁一般来说有以下2种方式:
表级锁
行级锁
页面锁(gap锁,间隙锁)
表共享读锁(Table Read Lock)
表独占写锁(Table Write Lock)
共享锁(s):又称读锁
排他锁(X):又称写锁
对于共享锁大家可能很好理解,就是多个事务只能读数据不能改数据。 对于排他锁大家的理解可能就有些差别,我当初就犯了一个错误,以为排他锁锁住一行数据后,其他事务就不能读取和修改该行数据,其实不是这样的。排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁。mysql InnoDB引擎默认的修改数据语句:update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用 select …for update
语句,加共享锁可以使用 select … lock in share mode
语句。所以加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。
间隙锁(Next-Key锁)
1,做MySQL集群
2,水平分表
3,垂直分表
其中题目和回答是比较大的字段,id,name,分数比较小。
如果我们只想查询id为8的学生的分数:select 分数 from aa where id=8;虽然知识只是查询分数,但是题目和回答这两个大字段也是要被扫描的,狠消耗性能。但是我们只关系分数,并不想查询题目和回答。这就可以使用垂直分割。我们可以把题目单独放到一张表中,通过id与aa表建立一对一的关系,同样将回答单独放到一张表中。这样我们查询aa中的分数的时候就不会扫描题目和回答。
其他方式:
利用merge存储引擎来实现分表(与水平分表类似):需要了解merge存储引擎的机制MySQL5.7.28_01_基于glibc的tar包安装
MySQL5.7.28_02_一张图片带你入门MySQL
MySQL5.7.28_03_一张图片带你进阶MySQL
MySQL5.7.28_03-1_一篇简单文章让你理解B- Tree和B+ Tree理解
MySQL5.7.28_03-2_MySQL中MyISAM与InnoDB引擎中的锁的简单理解
MySQL5.7.28_03-3_理解MySQL主从复制(也叫做主从同步)
MySQL5.7.28_03-4_MySQL 分布式ID方案总结
MySQL5.7.28_04_MySQL相关规范(实际工作中需要注意的)