Mysql高级
mysql的架构介绍
Linux安装Mysql
检查当前系统是否安装过mysql
- 在opt目录下打开命令行
- 查询命令:
rpm -qa|grep -i mysql
- 删除命令:
rpm -e rpm软件包名
安装Mysql服务端
- 安装
rpm -ivh Mysql-server-5.5.48...rpm
- 安装
安装mysql客户端
- 安装
rpm -ivh mysql-client...rpm
- 安装
查看mysql安装版本(是否安装成功)
mysqladmin --version
命令,类似java -version如果打出消息,即为成功。启动
service mysql start
查看是否开启:
ps -ef|grep mysql
关闭
service mysql stop
修改Mysql登录密码
- 启动服务之后,执行命令
/usr/bin/mysqladmin -u root password '123456'
- 通过
mysql -uroot -p123456
进行登录
- 启动服务之后,执行命令
设置mysql自启动
chkconfig --level 5 mysql on
开启chkconfig --list|grep mysql
查看- 【可选操作】
ntsysv
也是查看,如果[*]mysql带 *,就是自启动
配置文件
拷贝配置文件
- 5.5版本:
cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
- 5.6版本:
cp /usr/share/mysql/my-default.cnf /etc/my.cnf
- 5.5版本:
重新启动mysql
service mysql stop/start
登录
mysql -uroot -p123456
退出
exit
修改字符集
cd /etc
- 查看是否有my.cnf文件,
ls -1 my.cnf
vim my.cnf
- [client]节点下,socket下加上
default-character-set=utf-8
- [mysqld]节点下,port下加上
character_set_server=utf8
charactet_set_client=utf8
collation-server=utf8_general_ci
- [mysql]节点下,no-auto-rehash下加上
default-character-set=utf8
- esc,
wq!
保存退出 - 重启数据库,登录数据库,插入中文测试(新建的库才有用)
mysql安装目录介绍
查看安装目录ps -ef|grep mysql
路径 | 解释 | 备注 |
---|---|---|
/var/lib/mysql/ | mysql数据库的存放路径** | 重要 |
/usr/share/mysql | 配置文件目录 | |
/usr/bin | 相关命令目录** | 重要 |
/etc/init.d/mysql | 启停相关脚本 |
Mysql配置文件
二进制日志log-bin
用于主从复制
错误日志log-error
默认是关闭的,记录严重的警告和错误信息,每次启动关闭的信息
查询日志log
默认关闭,记录查询到的sql语句
数据文件
- 双系统
- window:\data
- linux:/var/lib/mysql,每一个目录代表一个同名的库
- frm文件:存放表结构
- myd文件:存放表数据
- myi文件:存放表索引
如何配置
- windows:my.ini文件
- linux:/etc/my.cnf文件
Mysql逻辑架构
连接层
服务层
Management Serveices & Utilities: 系统管理和控制工具
SQL Interface: SQL接口
接受用户的SQL命令,并且返回用户需要查询的结果。比如select from就是调用SQL InterfaceParser: 解析器
SQL命令传递到解析器的时候会被解析器验证和解析。Optimizer: 查询优化器。
SQL语句在查询之前会使用查询优化器对查询进行优化,即选取最优的方式执行。Cache和Buffer: 查询缓存。
如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。
引擎层
存储层
存储引擎
查看命令
- 方式一:看你的mysql现在已提供什么存储引擎:
show engines;
- 方式二:看你的mysql当前默认的存储引擎:
show variables like '%storage_engine%';
- 方式一:看你的mysql现在已提供什么存储引擎:
MyISAM和InnoDB
索引优化分析
整体优化策略:
- 慢查询的开启并捕获
- explain+慢sql分析
- show profile查询sql在mysql服务器里执行细节和生命周期情况
- sql数据库服务器的参数调优
性能下降sql慢,执行/等待时间长
- 查询语句写的烂
- 索引失效
- 单值
create index 索引名idx_user_name on 表名user(列名name)
- 复合
create index 索引名idx_user_name on 表名user(列名name)
- 单值
- 关联查询太多join(设计缺陷或不得已的需求)
- 服务器调优及各个参数设置(缓冲、线程数等)
常见通用的Join查询
机读sql执行顺序
-
注意:mysql不支持full join
全外连:
select * from tb_emp a left join tb_deptId b on a.deptId = b.id union #连接表,并去重 select * from tb_emp a right join tb_deptId b on a.deptId = b.id
全外连,中间部分去掉
select * from tb_emp a left join tb_deptId b on a.deptId = b.id where b.id is null union select * from tb_emp a right join tb_deptId b on a.deptId = b.id where a.id is null
索引
定义:是帮助mysql高效获取数据的数据结构。简单理解为:排好序的快速查找数据结构
除了数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。
一般索引本身也很大,以索引文件的形式存储在磁盘上
优势
- 类似大学图书馆的书目索引,提高数据检索的效率(树的高度),降低数据库的io成本
- 通过索引列对数据进行排序,降低数据排序的成本,降低了cpu成本
劣势
- 实际上索引也是一张表,表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的
- 虽然索引提高了查询速度,同时却会降低更新表的速度。每次更新表,还要更改索引信息。
- 要花时间研究建立最优秀的索引
索引的分类
- 单值索引:一个索引只包含单个列,一个表可以有多个单值索引
- 唯一索引:索引列的值必须唯一,但允许空值
- 复合索引:一个索引包含多个列
基本语法:
创建:
create [unique] index indexName on mytable(columnname); alter mytable add [unique] index[indexName] on (columnname);
删除:
drop index[indexName] on mytable;
查看:
show index from table_name
alter命令
alter table 表名 add primary key (列名):添加主键 alter table 表名 add unique 索引名(列名):创建索引的值必须是唯一的 alter table 表名 add index 索引名(列名):增加普通索引 alter table 表名 fulltext 索引名(列名):全文索引
哪些情况需要创建索引
- 主键自动建立唯一索引
- 频繁作为查询条件的字段
- 查询中与其他表关联的字段,外键关系建立索引
- 单值/组合索引的选择问题,组合索引性价比更高
- 查询中排序的字段,排序字段若通过索引去访问呢将大大提高排序速度
- 查询中统计或分组字段
不要创建索引
- 记录数据少
- 经常增删改
- where条件用不到的字段
- 过滤性不好
索引结构
B+Tree
性能分析
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,知道MYSQL是怎么处理SQL语句的
用法:explain+SQL语句
用处:
- 表的读取顺序
- 数据读取操作的操作类型
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
各字段的解释
- id:查询中执行select子句或操作表达顺序
- id相同,执行顺序从上到下
- id不同,id值越大,越先被执行
- id有相同有不同,越大越优先,其余顺序执行。
- derived衍生表,derived2就是Id为2查询出来的表作为衍生表。
- select_type:查询的类型,主要用于区别普通、联合、子查询等复杂查询
- simple:简单的select查询,查询中不包含子查询或union
- primary:查询中若包含任何复杂的子查询,最外层查询则被标记为
- subquery:在select或where列表中包含的子查询
- derived:在from列表中包含的的子查询被标记为derived(衍生),mysql会递归执行这些子查询,把结果放在临时表里
- union:若第二个select出现在union之后,则会标记为union;若union包含在from子句的子查询中,外层select将被标记为derived
- union result:从union表获得结果的select
- table:显示这一行的数据是关于哪张表的
- type:访问类型排列,显示查询使用了哪种类型
- 最好到最差:system>const>eq_ref>ref>range>index>all
- 一般来说,保证查询达到range级别,最好达到ref
- system:表只有一行记录,const类型的特例
- const:标识通过索引一次就查找到,const用于比较primary key 或者 unique索引。因为只匹配一行数据,所以很快。若where id = 1(唯一/主键索引确定)
- eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常用于主键或唯一索引扫描(多个表的唯一/主键索引确定)
- ref:非唯一性索引扫描,返回匹配某个单独值的所有行
- range:只检索给定范围的行,使用一个索引来选择行。一般来说就是between、<、>,in,这种范围扫描索引扫描比全表扫描好。
- index:全索引扫描,与all区别为index类型只遍历树,通常比all快,因为索引文件通常比数据文件小
- all:遍历全表以找到匹配的行
- possible_keys:显示可能应用在这张表中的索引,一个或多个。查询涉及到字段存在索引,但不一定被实际使用
- key:实际使用的索引。如果为Null,则没有使用索引。如果使用了覆盖索引,则该索引出现在key列表中
- key_len:表示索引中使用的字节数,显示的值为索引字段最大可能长度,并非实际使用长度。在不损失精度的情况下,长度越短越好。
- ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值
- rows:根据表统计信息及索引寻用情况,大致估算出找到所需的就所需要读取的行数,越小越好
- extra:包含不适合在其他列中显示但是十分重要的额外信息
- Using filesort:我们创建的索引,虽然mysql用索引来查找,但是排序却没有用到,而是自己在表内又进行了内部排序。Mysql无法利用索引进行排序称作“文件排序”(复合索引c1_c2_c3,where c1=’’,order by c3)
- Using temporary:使用了临时表保存中间结果,Mysql在对查询结果排序时使用临时表。常见排序order by,或分组查询group by(复合索引c1_c2,group by c2)
- Using index:表示响应的select操作使用了覆盖索引,避免访问了数据行。如果同时出现using where,表明索引被用类执行索引键值查找。如果每日有出现using where,表明索引用来读取数据而并非执行查找。
- 覆盖索引:建立的复合索引的个数和顺序,和查找时的个数和顺序相同。就是select的数据列只用从索引中就能取得,不必读取数据行,mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件。
- Using where:表明使用了where过滤
- using join buffer:使用了连接缓存
- impossible where:where子句的值总是false,不能用来获取任何元组
- select tables optimized away:(不常见)在没有group by子句下,对索引优化的一些操作
- distinct:(不常见)优化distinct操作,在找到第一个匹配的时候就停止找相同值的动作
索引优化
索引分析
单表
范围查询,后面的索引会失效
创建所有条件的索引
删除索引
创建新索引
#案例:查询category_id为1且comments大于1的情况下,view最多的article_id select id,author_id from article where category_id = 1 and comments>1 order by views desc limit 1; #第一次创建索引 create index idx_article_ccv on article(category_id,comments,views) #出现以下问题:type为range,用到了索引,但由于comments是范围查找,导致后面的views索引失效,出现Using fileSort #删除索引 drop index idx_article_ccv on article #第二次创建索引 create index idx_article_cv on article(category_id,views) #出现情况:type为ref,用到了索引,并且ref用到了常量,没有出现Using fileSort
两表
左右连接,索引建在从表上
#案例: select * from class left join book on class.card = book.card #建立索引 create index idx_class_card on class(card) #出现的情况:建在主表上,type为index,查找rows仍然是所有数据 #建立索引 create index idx_book_card on book(card) #出现的情况:建立在从表上,type为ref,并且ref是class.card,查找的rows变为1
三表
左右连接,索引建在从表
#案例: select * from class left join book on class.card = book.card left join phone on book.card = phone.card #建立索引 create index idx_book_card on book(card) #建立索引 create index idx_phone_card on phone(card) #出现的情况:建立在从表上,type为ref,并且ref是class.card、book.card,查找的rows变为1
join语句的优化:
- 尽可能减少join语句循环嵌套,永远用小表驱动大表(小表作为主表)
- 优先优化循环嵌套的内层循环
- 保证join语句中被驱动表上的Join条件字段已被索引
- 当无法保证被驱动表的join条件字段被索引且内存充足,调大joinbuffer的设置
索引失效
全值匹配:复合索引3个,用到的查询条件也是3个。
最左前缀法则:
- 带头大哥不能死:第一个索引没有用到,其他索引就会失效
- 中间兄弟不能断:第一个索引用到了,但第二个条件中没有用到,则后续的索引都不会用到
#符合索引c1,c2,c3,c4 select * from test03 where c1 = 'a1' and c3='a3' and c2 ='a2' #结果:c123都用到了索引,mysql在底层已经优化翻译
索引列上不做任何操作(计算、函数、(自动或手动)类型转换),会导致索引失效而转向全表扫描
在条件语句中,对索引列包裹有函数
#符合索引为(nameAgePosition),失效 select * from staffs where left(name,4) = 'judy'
范围查询,后面的索引会失效
#name用到索引,age用到range范围索引,pos失效 select * from staffs where name='judy' and age>25 and pos = 'manager' #复合索引c1,c2,c3,c4 select * from test03 where c1='a1' and c2='a2' and c4>'a4' and c3 = 'a3' #结果:4个均用到索引
尽量使用覆盖索引,减少select *
这样只会在索引中进行查找,而不需要进行io操作查找表中数据
select * from staffs where name='judy' and age=25 and pos='manager' #出现的情况:除了索引的列,其他列还需要在表中查找 select name,age,pos from staffs where name='judy' and age=25 and pos='manager' #出现的情况:只会在索引中查找。出现Using index select name,age,pos from staffs where name='judy' #出现的情况:也会用到索引中扫描,出现Using index select name,age,pos from staffs where name='judy' and age>25 and pos='manager' #出现的情况:type是ref,而不是range,因为查找的数据都是在索引中查找,级别就是ref,涉及到表中查找才会使range
使用不等于会导致索引失效
is null,is not null无法使用索引
like以通配符开头会导致索引失效
like百分号加右边
这种情况下,type是range级别
如果一定要用 %字符串%,为保证索引不失效,需要使用覆盖索引解决,查询的字段都需要在索引上。如果有一个不在就会导致索引失效从而全盘扫描。
字符串不加单引号会导致索引失效(自动做了类型转换,参考第三条)
少用or,索引会失效
案例
#复合索引c1,c2,c3,c4
select * from test where c1='a1' and c2='a2' and c4='a4' order by c3;
#结果:c1,c2用于查找,c3用来排序
select * from test03 where c1='a1' and c2='a2' order by 'c4';
#结果:c1,c2用到,c4没用到排序,产生filesort 内排序
select * from test where c1='a1' and c5='a5' order by c2,c3;
#结果:c1用到,c2,c3用于排序,无filesort
select * from test where c1='a1' and c5='a5' order by c3,c2;
#结果:c1用到,出现filesort
select * from test where c1='a1' and c2='a2' where order by c3,c2;
#结果:c1用到,因为c2是个常量,所以只有c3做了排序,所以不会出现filesort
select * from test where c1='a1' and c4='a4' group by c2,c3;
#结果:c1用到,c2,c3用于排序
select * from test where c1='a1' and c4='a4' group by c3,c2;
#结果,c1用到,出现using filesort,using temporary。
定值是常量,范围之后是失效,最后看排序。
group by分组前必排序,如果排序错乱,则会产生内排序和临时表
一般性建议
- 对于单值索引,尽量选择针对当前查询过滤性更好的索引
- 在选择组合索引,但其查询过滤性最好的字段应该放在最靠左的位置
- 在选择组合索引时,尽量选择能够包含当前查询中where字句更频繁的字段的索引
- 尽可能通过分析统计信息和调整查询的写法,来达到合适索引的目的
Order By 优化
#复合索引age_birth
select * from tbl where age > 20 order by age;
#结果:用到索引排序using index
select * from tbl where age > 20 order by birth;
#结果:using filesort
select * from tbl where age > 20 order by birth,age;
#结果: using filesort
select * from tbl where age > 20 order by age asc,birth desc;
#结果:using filesort
select * from tbl where age > 20 order by age desc,birth desc;
#结果:用到索引排序using index(同升、同降都能用到索引)
key a_b_c(a,b,c)
使用索引遵循最左前缀
order by a
order by a,b
order by a,b,c
order by a desc,b desc,c desc
如果where使用索引的最左前缀定义为常量,order by 能使用索引
where a = const order by b,c
where a = const and b = const order by c
where a = const and b > const order by b,c #这里虽然b是范围,但是a是常量和order的bc相连,故生效
索引**不能**进行排序的情况:
order by a asc,b desc,c desc #排序不一致
where g=const order by b,c #丢失a索引
where a=const order by c #丢失b索引
where a=const order by a,d #d不是索引的一部分
where a in (...) order by b,c #对于排序来说,多个相等条件也是范围查询
Mysql支持两种方式排序:FileSort和Index,Index效率高,它指mysql扫描索引本身完成排序,Filesort方式为内排序
会index方式排序的情况:
mysql能为排序与查询使用相同的索引
- order by语句使用索引最左前列(最左前缀原则)
- 使用where子句与order by子句条件列组合满足索引最左前列
filesort的两种排序算法:
- 双路排序:(在mysql5之前)进行两次IO操作,数据可以全部取出
- 单路排序:一般进行一次IO操作,性能优于双路。但数据只能取出sort_buffer缓冲区大小,如果没有得到需要的结果,还需要继续取出,从而出现多次IO操作,有可能不如双路。
- 优化策略:
- 避免使用select *,它会增加字段大小从而占满缓冲区
- 如果查询的字段大小总和小于max_length_for_sort_data,就会用单路,否则会用多路
- 两种算法都有可能占满sort_buffer,超出后会进行多次取数据的IO操作
- 尝试提高sort_buffer_size
- 尝试提高max_length_for_sort_data
- 避免使用select *,它会增加字段大小从而占满缓冲区
- 优化策略:
Group by 优化:
- group by 实质是先排序后进行分组,遵循索引的最左前缀原则
- 当无法使用索引列,增大max_length_for_sort_data、sort_buffer_size
- where高于having,能写在where限定的条件就不要用在having
查询截取分析
in与exists的优化
小表驱动大表,即小的数据集驱动大的数据集
当B表的数据集小于A表的数据集时,in优于exists
select * from A where id in (select id from B) 等价于 for select id from B #外循环数据集小 for select * from A where A.id = B.id #内循环数据集大
当A表数据集小于B表的数据集时,用exists优于in
select * from A where exists (select 1 from B where B.id = A.id) 等价于 for select * from A #外循环数据集小 for select * from B where B.id = A.id #内循环数据集大
意思就是:将主查询的数据,放到子查询中做条件验证,根据验证结果(true或false)来决定主查询的数据结果是否得以保留
Exists: 先查询一次外SELECT,后去子查询里做验证。IN:先查询子SELECT,然后用外表的一个记录做验证。
慢查询日志
是mysql提供的一种日志记录,它用于记录mysql响应时间超过阈值的语句。具体运行时间超过long_query_time
默认情况下,mysql数据库没有开启慢查询日志,需要手动配置参数。不调优的时候,一般建议关闭
- 查看是否开启:
show variables like '%slow_query_log%'
- 开启:
set global slow_query_log=1
- 开启只会对当前数据库生效,重启mysql会失效
- 【可选】指定默认路径:
slow_query_log_file
,系统默认为:host_name-slow.log
- 查看阈值:
show variables like 'long_query_time%'
,默认为10s - 设置阈值:
set global long_query_time=3
- 需要重新连接或新开一个会话才会看到生效
- 查看抓取了几条慢查询sql:
show global status like '%Slow_queries%'
慢查询日志分析工具mysqldumpslow
批量插入数据脚本
案例需求:插入50w个记录,要求员工名和部门编号为随机
建表
# 新建库 create database bigData; use bigData; #1 建表dept CREATE TABLE dept( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, dname VARCHAR(20) NOT NULL DEFAULT "", loc VARCHAR(13) NOT NULL DEFAULT "" ) ENGINE=INNODB DEFAULT CHARSET=UTF8 ; #2 建表emp CREATE TABLE emp ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/ ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/ job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/ mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/ hiredate DATE NOT NULL,/*入职时间*/ sal DECIMAL(7,2) NOT NULL,/*薪水*/ comm DECIMAL(7,2) NOT NULL,/*红利*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/ )ENGINE=INNODB DEFAULT CHARSET=UTF8 ;
设置参数
log_bin_trust_function_creators
- 由于开启慢查询日志,需要配置一个参数,否则创建函数会报错
DETERMINISTIC
show variables like 'log_bin_trust_function_creators';
set global log_bin_turst_function_creators=1;
- 由于开启慢查询日志,需要配置一个参数,否则创建函数会报错
创建函数,保证每条数据都不同
随机产生字符串
DELIMITER $$ CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) BEGIN ##方法开始 DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; ##声明一个 字符窜长度为 100 的变量 chars_str ,默认值 DECLARE return_str VARCHAR(255) DEFAULT ''; DECLARE i INT DEFAULT 0; ##循环开始 WHILE i < n DO SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1)); ##concat 连接函数 ,substring(a,index,length) 从index处开始截取 SET i = i + 1; END WHILE; RETURN return_str; END $$
随机产生部门编号
#用于随机产生部门编号 DELIMITER $$ CREATE FUNCTION rand_num( ) RETURNS INT(5) BEGIN DECLARE i INT DEFAULT 0; SET i = FLOOR(100+RAND()*10); RETURN i; END $$
创建存储过程,用于插入数据
emp表
DELIMITER $$ CREATE PROCEDURE insert_emp10000(IN START INT(10),IN max_num INT(10)) /*参数1:起始员工id,参数2:插入的数据量*/ BEGIN DECLARE i INT DEFAULT 0; #set autocommit =0 把autocommit设置成0 ;事务开启 SET autocommit = 0; REPEAT ##重复,先执行后判断 SET i = i + 1; INSERT INTO emp10000 (empno, ename ,job ,mgr ,hiredate ,sal ,comm ,deptno ) VALUES ((START+i) ,rand_string(6),'SALESMAN',0001,CURDATE(),FLOOR(1+RAND()*20000),FLOOR(1+RAND()*1000),rand_num()); UNTIL i = max_num ##直到 上面也是一个循环 END REPEAT; ##满足条件后结束循环 COMMIT; ##执行完成后一起提交 END $$
dept表
#执行存储过程,往dept表添加随机数据 DELIMITER $$ CREATE PROCEDURE insert_dept(IN START INT(10),IN max_num INT(10)) /*参数1:起始部门id,参数2:插入的数据量*/ BEGIN DECLARE i INT DEFAULT 0; SET autocommit = 0; REPEAT SET i = i + 1; INSERT INTO dept (deptno ,dname,loc ) VALUES (START +i ,rand_string(10),rand_string(8)); UNTIL i = max_num END REPEAT; COMMIT; END $$
调用存储过程,插入数据
DELIMITER ; CALL insert_dept(100,10); CALL insert_emp(100001,500000);
Show Profile
用来分析当前会话中语句执行的资源消耗,记录每一步花费了多少时间
默认情况下,处于关闭状态,并保存最近15此运行结果
步骤
- 查看Mysql版本是否支持:
show variables like 'profiling'
- 开启功能:
set profiling = on
- 运行sql:执行一些sql语句,用于之后的记录
- 查看结果:
show profiles
- 诊断sql(查询这个sql的整个生命周期每个阶段的时间):
show profile cpu,block io for query 号码
,这里的号码是上一步查出来的id - 结论:出现有以下几点,需要优化
- converting heap to myisam 查询结果太大,内存不够用
- creating tem table 创建临时表
- 拷贝数据到临时表
- 用完再删除
- copying to tmp table on disk 把内存中临时表复制到磁盘
- Locked
全局查询日志
作用:用于把所有sql语句,将会记录在mysql库里的general_log表中,可以用下面的指令查看
select * from mysql.general_log;
注意:不要在生产环境开启这个功能
步骤
set global general_log = 1;
set global log_output='TABLE'