mysql高阶应用-索引、并发控制、事务、日志

一、索引

1.使用索引优缺点:
优点:

  • 索引可以降低服务需要扫描的数据量,减少了IO次数
  • 索引可以帮助服务器避免排序和使用临时表
  • 索引可以帮助将随机I/O转为顺序I/O

缺点:

  • 索引占用额外空间,影响插入速度;一旦数据更新(如插入,删除),需要维护索引(数据重新排序);

建议:查询频率高的建立索引,变更数据多的要考虑是否需要建立索引

2.索引原理:
将物理上存放的不规则的,无顺序的数据,通过索引在逻辑上有规则有顺序的连接在一起,提高查询效率。

  • 数值顺序:
  • 字符顺序:与对应的字符集的字符序相关,如按字母顺序:ab与aa,第一个字符相同的情况下,对第二个字符排序,以此类推

3.查询方式:

  • 连续查询:如查年龄10~20岁的学生信息
  • 单独查询: 如查年龄为20岁的学生信息

4.分类:

  • B+TREE:
  • HASH:
  • R TREE:
  • 聚簇(集)索引:数据和索引存储在一起
  • 非聚簇索引:数据和索引分开存放
  • 简单索引(单列索引):仅一个字段充当索引
  • 复合索引:两个以上字段作为索引(需要指定索引字段顺序);第一个索引固定的情况下,- 第二个索引才是按顺序排序的,跳过第一个字段直接查询第二个字段,无法利用索引
  • 主键索引:
    主键和唯一键的区别:
    主键只能有一个,唯一键可以有多个;
    主键值不能为空,唯一键可以为空;
  • 唯一键索引:保证字段值都是唯一的,如手机号
  • 二级(辅助)索引
  • 稠密索引、稀疏索引:是否索引了每一个数据项
  • 简单索引、组合索引
  • 左前缀索引:取前面的字符做索引
  • 覆盖索引:从索引中即可取出要查询的数据,性能高

5.B-Tree 与 B+Tree

(1)B-Tree特性
磁盘块中存放的数据块(每个数据块包含的记录信息字段数越少)数越多,查询越快(树深越浅)

(2)B+Tree特性
(1)每个数据块存放的是索引字段的值,不存放具体记录的完整数据,记录完整信息放在叶子节点
(2)查询速度都一样,都要查询到叶子节点;
(3)链表:指定下一个数据块位置

6.建立B+tree索引条件:
(1)在查询的where查询条件建立索引;
(2)查询记录数重复比较少的情况,如性别建立索引无意义,可在电话号码上建立索引
(3)读多写少情况

7.B-Tree与B+Tree的区别(优缺点)
B-Tree 缺点
对应范围查找无能为力,范围内每个数都要从根找起

8.管理索引

  • 创建索引
	CREATE INDEX [UNIQUE] index_name ON tbl_name (index_col_name[(length)],...);
ALTER TABLE tbl_name ADD INDEX index_name(index_col_name);
help CREATE INDEX;
  • 查看索引
SHOW INDEXES FROM [db_name.]tbl_name;
  • 删除索引
DROP INDEX index_name ON tbl_name;
ALTER TABLE tbl_name DROP INDEX index_name(index_col_name);
  • 查看索引的使用
SET GLOBAL userstat=1;
SHOW INDEX_STATISTICS;
  • 优化表空间:
OPTIMIZE TABLE tb_name;

9.分析索引有效性
explain:获取查询执行计划信息,用来查看查询优化器如何执行查询
EXPLAIN Output Format 输出格式参见:
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

添加索引与未添加索引时间效率对比

二、并发控制:锁

锁类型:

  • 读锁:共享锁,只读不可写(包括当前事务) ,多个读互不阻塞
  • 写锁:独占锁,排它锁,写锁会阻塞其它事务(不包括当前事务)的读和写

锁粒度:

  • 表级锁
  • 行级锁

锁调用方式:

  • 隐式锁:由存储引擎自动施加锁
  • 显式锁:用户手动请求

显示调用锁

LOCK TABLES	#加锁
    tbl_name [[AS] alias] lock_type
    [, tbl_name [[AS] alias] lock_type] ...

lock_type:
    READ [LOCAL]
  | [LOW_PRIORITY] WRITE

UNLOCK TABLES  #解锁

关闭正在打开的表(清除查询缓存),通常在备份前加全局读锁

FLUSH TABLES [tb_name[,...]] [WITH READ LOCK]

查询时加写或读锁

SELECT clause [FOR UPDATE | LOCK IN SHARE MODE]

三、事务

ACID特性:

  • A:atomicity原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚
  • C:consistency一致性;数据库总是从一个一致性状态转换为另一个一致性状态
    如银行转账,A账户转账给B账户,A减去10000,B加10000;A不减,B不加,不会出现转来转去把钱转丢
  • I:Isolation隔离性;一个事务所做出的操作在提交之前,是不能为其它事务所见;隔离有多种隔离级别,实现并发
    如以下场景:原来工资10000,现正在执行加1000事务,这个事务没有结束,可能会撤销;另一个事务查看工资记录;不同隔离级别查看的结果不一样。
  • D:durability持久性;一旦事务提交,其所做的修改会永久保存于数据库中
    类比开会后的决议案

作用域:
对DML语句作用:
对DDL语句没有作用:

启动事务:

  • BEGIN
  • BEGIN WORK
  • START TRANSACTION

结束事务:

  • COMMIT:提交
  • ROLLBACK: 回滚

事务隔离级别:
从上到下越来越严格:

  • read uncommitted:A事务commit前,B事务可查看A正在修改的数据
  • read committed:A事务commit的某个时间段在更新某个数据,在B事务里不同时间读到的数据不一样,可能A事务commit后的结果和B事务查看的结果不一致,导致不可连续读。
  • repeatable read:(mysql默认设置)A事务commit前某个时间段在更新某个数据,B事务看的数据不变,可连续读;但A事务commit更新后的数据,B事务看到的数据仍然是未变更前的数据,产生幻读。配合备份数据库,备份数据期间,备份的数据时稳定不变的。
  • serializabile:可串行化,未提交的读事务阻塞修改事务,或者未提交的修改事务阻塞读事务。导致并发性能差

在这里插入图片描述

事务死锁

四、日志

日志分类:

  • 事务日志 transaction log
  • 错误日志 error log
  • 通用日志 general log
  • 慢查询日志 slow query log
  • 二进制日志 binary log
  • 中继日志 reley log

(一)事务日志:

#有#注释的是5.5.60-MariaDB的变量
MariaDB [hellodb]> show variables like '%innodb_log%';
+-------------------------------+------------+
| Variable_name                 | Value      |
+-------------------------------+------------+
| innodb_log_arch_dir           |            |
| innodb_log_arch_expire_sec    | 0          | 
| innodb_log_archive            | OFF        |
| innodb_log_block_size         | 0          |  #日志块大小
| innodb_log_buffer_size        | 16777216   |	#日志缓冲区大小
| innodb_log_checksum_algorithm | DEPRECATED |
| innodb_log_checksums          | ON         |
| innodb_log_compressed_pages   | ON         |
| innodb_log_file_size          | 50331648   |	#日志文件大小
| innodb_log_files_in_group     | 2          |	#事务文件路径
| innodb_log_group_home_dir     | ./         |	#事务文件路径
| innodb_log_optimize_ddl       | ON         |
| innodb_log_write_ahead_size   | 8192       |
+-------------------------------+------------+

事务日志文件:

#5.5.60-MariaDB 默认单个事务日志文件大小5M
#10.2.25-MariaDB-log默认48M
#建议事务日志大小设置大一些数量多一些,防止因事务日志太小,大事务来回复盖日志文件无法执行下去
[root@CentOS7 ~]#ll /var/lib/mysql/
-rw-rw---- 1 mysql mysql  48M Jul 11 10:24 ib_logfile0
-rw-rw---- 1 mysql mysql  48M Jul 10 19:27 ib_logfile1

innodb_flush_log_at_trx_commit=1
1 默认情况下,日志缓冲区将写入日志文件,并在每次事务后执行刷新到磁盘。 这是完全遵守ACID特性
0 提交时没有任何操作; 而是每秒执行一次日志缓冲区写入和刷新。 这样可以提供更好的性能,但服务器崩溃可能丢失最后一秒的事务
2 每次提交后都会写入日志缓冲区,但每秒都会进行一次刷新。 性能比0略好一些,但操作系统或停电可能导致最后一秒的交易丢失
3 模拟MariaDB 5.5组提交(每组提交3个同步),此项MariaDB 10.0支持

建议将事务日志存放到单独磁盘,至少是单独分区

[root@CentOS7 ~]#vim /etc/my.cnf
innodb_log_group_home_dir=/data/mariadb
[root@CentOS7 ~]#ll -d /data/mariadb/
[root@CentOS7 ~]#chown mysql:mysql /data/mariadb/
[root@CentOS7 ~]#ll -d /data/mariadb/
[root@CentOS7 ~]#systemctl restart mariadb
[root@CentOS7 ~]#ll -h /data/mariadb/

在这里插入图片描述

(二)错误日志

记录内容
1.mysqld启动和关闭过程中输出的事件信息
2.mysqld运行中产生的错误信息
3.event scheduler运行一个event时产生的日志信息
4.在主从复制架构中的从服务器上启动从服务器线程时产生的信息

#5.5.60-MariaDB 默认错误日志路径/var/log/mariadb/mariadb.log
#10.2.25-MariaDB-lo  默认未指定错误日志路径
MariaDB [hellodb]>show global variables like 'log_error';

设置错误日志路径:

[root@CentOS7 ~]#vim /etc/my.cnf
log-error=/data/mariadb/mariadb.log

(三)通用日志

记录数据库的操作,如各种SQL语句;对性能有影响,一般用于排错时启用

#默认通用日志是关闭的,并且mariadb安装目录中没有CentOS7.log文件,只有开启通用日志重启服务后才生成
#general_log=ON|OFF
#general_log_file=HOSTNAME.log
#log_output=TABLE|FILE|NONE  通用日志输出方式,table是放到mysql.general_log表中
MariaDB [hellodb]> show variables like 'general%';
+------------------+-------------+
| Variable_name    | Value       |
+------------------+-------------+
| general_log      | OFF         |
| general_log_file | CentOS7.log |
+------------------+-------------+

MariaDB [hellodb]> show variables like 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+

通用日志放到文件方式:/var/lib/mysql/CentOS7.log
在这里插入图片描述
通用日志放到数据库方式:mysql.general_log
在这里插入图片描述

(四)慢查询日志

#默认慢查询日志记录查询时间:10s
MariaDB [mysql]> show variables like 'long%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
#默认慢查询日志启用状态:未启用
#mariadb安装目录中没有CentOS7-slow.log文件,只有开启通用日志重启服务后才生成
MariaDB [mysql]> show variables like 'slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+
MariaDB [hellodb]> show variables like 'log_queries_not_using_indexes';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF   |
+-------------------------------+-------+

#是否启用查询执行过程详细信息
MariaDB [hellodb]> show variables like 'profiling';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| profiling     | OFF   |
+---------------+-------+

慢查询日志常用变量

slow_query_log=ON|OFF 	 #开启或关闭慢查询
long_query_time=N 	#慢查询的阀值,单位秒
slow_query_log_file=HOSTNAME-slow.log 	#慢查询日志文件路径,主机名-slow.log
log_slow_filter = admin|filesort|filesort_on_disk|full_join|full_scan|query_cache|query_cache_miss|tmp_table|tmp_table_on_disk
#上述查询类型且查询时长超过long_query_time,则记录日志
log_queries_not_using_indexes=ON #不使用索引的查询语句或使用全索引扫描的语句,不论是否达到慢查询阀值的语句是否记录日志,默认OFF,即不记录
log_slow_rate_limit = 1 #多少次查询才记录,mariadb特有
log_slow_verbosity= Query_plan,explain 	#记录内容

启用慢查询日志配置:

[root@CentOS7 data]#vim /etc/my.cnf
slow_query_log
long_query_time=3 #设置超过3秒记录慢查询日志
profiling

慢查询语句

MariaDB [hellodb]> select sleep(1) from students;

在这里插入图片描述
查看某条慢查询语句具体执行时间

MariaDB [hellodb]> set profiling=on;
MariaDB [hellodb]> select sleep(1) from students;
MariaDB [hellodb]> show profiles;
+----------+------------+---------------------------------+
| Query_ID | Duration   | Query                           |
+----------+------------+---------------------------------+
|        1 | 0.00035217 | show variables like 'profiling' |
|        2 | 4.00351785 | select sleep(1) from teachers   |
|        3 | 0.00005712 | show profiles for query 2       |
+----------+------------+---------------------------------+
3 rows in set (0.00 sec)

MariaDB [hellodb]> show profile for query 2;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000127 |开始
| checking permissions | 0.000007 |检查权限
| Opening tables       | 0.000012 |打开表
| After opening tables | 0.000006 |打开表后
| System lock          | 0.000004 |系统锁
| Table lock           | 0.000002 |锁表
| After table lock     | 0.000004 |锁表后
| init                 | 0.000016 |初始化
| optimizing           | 0.000007 |优化
| statistics           | 0.000014 |统计
| preparing            | 0.000008 |准备
| executing            | 0.000003 |执行
| Sending data         | 0.000078 |发送数据
| User sleep           | 1.000871 |
| User sleep           | 1.000847 |
| User sleep           | 1.001120 |
| User sleep           | 1.000285 |
| end                  | 0.000014 |结束
| query end            | 0.000023 |查询结束
| closing tables       | 0.000008 |关闭表
| freeing items        | 0.000006 |释放项目
| updating status      | 0.000013 |更新状态
| logging slow query   | 0.000041 |记录慢查询
| cleaning up          | 0.000002 |清理
+----------------------+----------+

注:
1.执行的事务中,如果有插入数据的操作,在事务结束前,除了事务日志文件大小在变大,同时数据文件大小也会随事务中插入数据量变大;但是如果事务以rollback回滚方式结束事务,则数据文件显示大小并没有变化;
2.如果此时不通过事务再插入数据,在为达到之前事务插入的数据量前,数据文件大小显示一直没有变化,直到插入数据量大于之前事务准备插入的数据量,数据文件大小才不断增加!
3.即使把表情况,数据文件大小仍然不会缩减

[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #10K
[root@CentOS7 ~]#msyql -uroot -p
MariaDB [hellodb]> begin;
MariaDB [hellodb]> call sp_testlog;   #创建testlog表并插入10万条数据的存储过程
MariaDB [hellodb]> rollback;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #12M
MariaDB [hellodb]> call sp_testlog;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #12M
MariaDB [hellodb]> call sp_testlog;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #24M 
MariaDB [hellodb]> delete from testlog;
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #24M
MariaDB [hellodb]> optimize tables testlog; #优化数据库
[root@CentOS7 ~]#ll -h /var/lib/mysql/hellodb/teachers.ibd #0M

(五)客户端日志

#用户家目录.mysql_history存放客户端执行的SQL语句
[root@CentOS7 ~]#cd
[root@CentOS7 ~]#ll -a
[root@CentOS7 ~]#cat .mysql_history

在这里插入图片描述

(六)二进制日志

记录SQL语句,记录对数据库的增删改,不记录查操作;日志不像事务日志有覆盖现象,日志一直累积。
强烈建议: 二进制日志单独存放磁盘,至少单独分区

#两个变量都启用才行
MariaDB [hellodb]> show variables like 'sql_log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_bin   | ON    |
+---------------+-------+
1 row in set (0.00 sec)

MariaDB [hellodb]> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
+---------------+-------+
1 row in set (0.00 sec)

#log_bin必须写配置文件开启
#sql_log_bin用于临时开启、关闭二进制日志;会话级变量,只能在一个ssh的shell窗口临时关闭
MariaDB [hellodb]> set log_bin=on;
ERROR 1238 (HY000): Variable 'log_bin' is a read only variable

二进制日志相关变量

sql_log_bin=ON|OFF	#否记录二进制日志,默认ON
log_bin=/PATH/BIN_LOG_FILE	#指定文件位置;默认OFF,表示不启用二进制日志功能,上述两项都开启才可
binlog_format=STATEMENT|ROW|MIXED #二进制日志记录的格式,默认STATEMENT,建议最好改为ROW,其次使用Mixed
max_binlog_size=1073741824	#单个二进制日志文件的最大体积,到达最大值会自动滚动,默认为1G
#说明:文件达到上限时的大小未必为指定的精确值
sync_binlog=1|0	#设定是否启动二进制日志即时同步磁盘功能,默认0,由操作系统负责同步日志到磁盘考虑性能选择0,考虑数据安全性选1
expire_logs_days=N	#二进制日志可以自动删除的天数。 默认为0,即不自动删除

设置开启二进制日志配置:

[root@CentOS7 ~]#mkdir /data/logbin
[root@CentOS7 ~]#chown mysql.mysql /data/logbin/
[root@CentOS7 ~]#vim /etc/my.cnf
log_bin=/data/logbin/mysql-bin   #log_bin=文件名路径+前缀,不写按默认路径和文件名前缀生成
binlog_format=row     #二进制日志记录形式
[root@CentOS7 data]#systemctl restart mariadb
[root@CentOS7 data]#ll /var/lib/mysql/
	CentOS7-bin.000001	#10.2.25-MariaDB-lo 默认二进制文件名
[root@CentOS7 data]#ll /var/lib/mysql/
	mariadb-bin.000001	#5.5.60-MariaDB 默认二进制文件名

在这里插入图片描述
如何查看二进制文件?
(1)数据库自带命令方式查看:

#查看所有二进制日志文件
MariaDB [hellodb]> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |  29078035 |
+------------------+-----------+
1 row in set (0.00 sec)

MariaDB [hellodb]> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |  29078035 |
+------------------+-----------+
1 row in set (0.00 sec)

#查看当前正在使用的二进制日志文件
#Position 通过大小标记日志位置,用于数据库还原判定起始位置
MariaDB [hellodb]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 29078035 |              |                  |
+------------------+----------+--------------+------------------+

#以文件形式查看二进制文件
MariaDB [hellodb]> show binlog events in 'CentOS7-bin.000001';
#查看某个位置之后的
MariaDB [hellodb]> show master status;
MariaDB [hellodb]> insert students (name,age) values('xiaomi',30);
MariaDB [hellodb]> show master status;
MariaDB [hellodb]> show binlog events in 'CentOS7-bin.000001' from 54756314;
+--------------------+----------+------------+-----------+-------------+---------------------------------------------------------------+
| Log_name           | Pos      | Event_type | Server_id | End_log_pos | Info                                                          |
+--------------------+----------+------------+-----------+-------------+---------------------------------------------------------------+
| CentOS7-bin.000001 | 54756314 | Gtid       |         1 |    54756356 | BEGIN GTID 0-1-200003                                         |
| CentOS7-bin.000001 | 54756356 | Intvar     |         1 |    54756388 | INSERT_ID=27                                                  |
| CentOS7-bin.000001 | 54756388 | Query      |         1 |    54756504 | use `hellodb`; insert students (name,age) values('xiaomi',30) |
| CentOS7-bin.000001 | 54756504 | Xid        |         1 |    54756535 | COMMIT /* xid=600027 */                                       |
+--------------------+----------+------------+-----------+-------------+---------------------------------------------------------------+

在这里插入图片描述

(2)客户端工具查看二进制日志:mysqlbinlog

使用语法

mysqlbinlog [OPTIONS] log_file…
--start-position=# 指定开始位置
--stop-position=#
--start-datetime=
--stop-datetime=
时间格式:YYYY-MM-DD hh:mm:ss
--base64-output[=name]
-v -vvv
[root@CentOS7 data]# mysqlbinlog --start-position=54756314 /var/lib/mysql/CentOS7-bin.000001
[root@CentOS7 data]# mysqlbinlog --start-position=54756314 /var/lib/mysql/CentOS7-bin.000001 -v #-v在最后能看到SQL语句

加v与不加v的区别:
不加v:
在这里插入图片描述
加v:
在这里插入图片描述
清除指定二进制日志:
PURGE { BINARY | MASTER } LOGS
{ TO ‘log_name’ | BEFORE datetime_expr }
示例:
PURGE BINARY LOGS TO ‘mariadb-bin.000003’;删除3之前的日志
PURGE BINARY LOGS BEFORE ‘2019-01-23’;
PURGE BINARY LOGS BEFORE ‘2019-03-22 09:25:30’;
删除所有二进制日志,index文件重新记数

RESET MASTER [TO #]; 删除所有二进制日志文件,并重新生成日志文件,文件名从#开始记数,默认从1开始,一般是master主机第一次启动时执行,MariaDB10.1.6开始支持TO #
切换日志文件:
FLUSH LOGS;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章