mysql专栏为你弥补这块的短板
后续我会在这块给大家带来mysql方面的知识,分享我在这块的经验。
mysql学习是一个漫长的过程,我希望大家能够不要浮躁,静下心来好好的学习基础知识,先把心法学会了,招式就是千变万化。平时我们使用数据库,看到的通常是一个整体。比如,你有一个最简单的表,表里有一个字段X、下面有一个执行语句:
mysql>select * from mytable where X=?;
或者更加复杂的语句。。。我这里就不在举例了。
我们看到给出一个语句,如果数据库有数据就会返回相应的结果。却不知道这条语句在MYSQL内部是如何执行的,我今天就给大家拆解一下MYSQL,希望这个拆解过程能让你对MYSQL有更深入的理解,这样我们遇到一些问题,或者异常我们能够快速的定位并且解决问题。
先看一下MYSQL官方的架构:
连接器
第一步,你会先连接到数据库,这个时候就是mysql连接器负责跟客户端建立连接,获取权限,管理连接。
linux命令连接mysql如下:
mysql -h&ip -P&port -u&username -p&password
不建议直接输入密码,存在安全隐患,最好直接-p enter 输入你的密码
在完成和服务器端TCP的三次握手后,就会验证身份,如果用户名和密码不对就会提示ERROR 1045 (28000): Access denied for user ‘meiling’@‘yourip’ (using password: YES)
如果登录成功后,我们在通过root权限对其修改权限,是不影响已经登录后权限的限制。我就不列出来了,大家可以自己尝试一下。
连接完成后,我们不操作任何命令,连接就处于空闲状态,我们用show processlist看看情况。
可以看到状态是 "sleep"就是空闲状态客户端很久都没操作,连接器就会自动断开。这个时间的参数可以看 wait_timeout,默认是8小时。
mysql> show variables like '%wait_timeout%';
+--------------------------+----------+
| Variable_name | Value |
+--------------------------+----------+
| innodb_lock_wait_timeout | 50 |
| lock_wait_timeout | 31536000 |
| wait_timeout | 28800 |
+--------------------------+----------+
3 rows in set
mysql>
我们可以看到是28800秒,换算成小时就是8个小时。你们可以自己看一下这个参数。
数据库经典8小时问题,就是这个默认参数如果发现一个连接的空闲时间超过8小时,将会在数据库端自动关闭这个连接。而数据源并不知道这个连接已经关闭了,当它将这个无用的连接返回给某个dao时,dao就会报无法获取connection异常。
所以我们可以针对这个参数来防止线上问题的发生哦,这个比较隐患。
1.我们可以适当的调整timeout的大小。
2.通过应用层当有空闲的连接的时候,就去激活一下,免得过期造成连接丢失。
数据的连接我们尽量的减少连接次数,连接的过程非常的复杂,太耗费资源,基本上都是长连接。 案例:有一次我们线上的数据库宕机了,发现非常多的连接导致内存涨的非常的快,长期累积的长连接导致我们内存占用过大,被系统强制杀掉了mysql进程。 原因分析:就是因为mysql在执行过程中使用的内存是在连接对象管理的,这些资源只会在连接断开后才会释放。 1,我们就在应用程序里面定期断开长连接,具体的实现我会专门有一篇文章(如何断开连接) 2,通过mysql_reset_connection方式来重置连接。下面是mysql官方提供的api说明
27.8.7.60 mysql_reset_connection()
int mysql_reset_connection(MYSQL *mysql)
说明
重置连接以清除会话状态。
mysql_reset_connection() 具有类似于 mysql_change_user() 的效果或自动重新连接,但连接未关闭并重新打开,并且未执行重新认证。见 Section 27.8.7.3, “mysql_change_user()” )并参见 Section 27.8.20, “C API Automatic Reconnection Control” )。
与连接相关的状态受影响如下:
回滚任何活动事务并重置自动提交模式。
释放所有表锁。
所有 TEMPORARY 表都已关闭(并已删除)。
会话系统变量重新初始化为相应的全局系统变量的值,包括由 SET NAMES 等语句隐式设置的系统变量。
用户变量设置丢失。
准备好的声明已经发布。
HANDLER 变量已关闭。
LAST_INSERT_ID() 的值重置为0。
使用 GET_LOCK() 获取的锁定被释放。
返回值
成功归零。如果发生错误,则为非零。
查询缓存
这个很简单,就是一个key-value的方式。
假如一条sql语句 select * from T where id=1;就会通过key是sql语句去map中查询是否有这条语句,如果有就直接返回,没有就执行后面的流程,把数据通过key-value的方式存储。
查看mysql是否开启缓存,执行如下命令:
mysql> show variables like '%query_cache_type%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| query_cache_type | ON |
+------------------+-------+
1 row in set (0.00 sec)
这个可以看到mysql是否开启了缓存。
但是实际使用的我个人觉得没什么必要打开缓存,缓存命中非常的低,我们的业务经常在更改变化,如何一旦有表数据发生变化,缓存就会清除。所以实战中我们是不会打开缓存的。
命令解析层
如果缓存没有命中的话,就会分析当前的sql,分析当前的语句是查询,还是ddl,还是其他的命令。
mysql>select * from mytable where X=?; //继续解说这条
我们输入的select 这个关键词就会识别出来是查询模块,在分别把mytable识别成表名 mytable ,把字符串识X别成列X。
后面就会做语法的分析,如果语法不对就会提示你错误。
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘ad’ at line 1
我们只需要关注的是 "user near"的内容,基本上就可以知道是什么错误了。
优化器
经过分析器后,mysql就知道你要做什么了,在调用执行器钱,还要做一些优化的处理。
优化器就是选择哪种方案去执行我们的sql。
简单的使用 OPTIMIZER_TRACE
查看是否开启优化器
mysql> show variables like '%optimizer_trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name | Value |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace | enabled=off,one_line=off |
| optimizer_trace_features | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit | 1 |
| optimizer_trace_max_mem_size | 16384 |
| optimizer_trace_offset | -1 |
+------------------------------+----------------------------------------------------------------------------+
开启优化器
mysql> set session optimizer_trace='enabled=on';
Query OK, 0 rows affected
mysql> show variables like '%optimizer_trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name | Value |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace | enabled=on,one_line=off |
| optimizer_trace_features | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit | 1 |
| optimizer_trace_max_mem_size | 16384 |
| optimizer_trace_offset | -1 |
+------------------------------+----------------------------------------------------------------------------+
5 rows in set
//执行一条查询语句
mysql> select * from oc_user where cid='e7cf68e15ba3480f';
+-----+------------------+----------+-----------+----------+-------------+---------+-------+-----------+------------+------------+--------+---------------------+------------+
| id | cid | nickname | username | password | phone | iconURL | email | ipaddress | devicetype | macaddress | frozen | createtime | updatetime |
+-----+------------------+----------+-----------+----------+-------------+---------+-------+-----------+------------+------------+--------+---------------------+------------+
| 129 | e7cf68e15ba3480f | NULL | ac_3Fhtni | NULL | 13966789831 | NULL | NULL | NULL | NULL | NULL | NULL | 2017-11-27 14:18:56 | NULL |
+-----+------------------+----------+-----------+----------+-------------+---------+-------+-----------+------------+------------+--------+---------------------+------------+
1 row in set
查看优化器如何执行的
mysql> select trace from information_schema.optimizer_trace;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| trace |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| {
"steps": [
{
"join_preparation": { //优化准备阶段
"select#": 1,
"steps": [
{
//表示出来查询的sql语句
"expanded_query": "/* select#1 */ select `oc_user`.`id` AS `id`,`oc_user`.`cid` AS `cid`,`oc_user`.`nickname` AS `nickname`,`oc_user`.`username` AS `username`,`oc_user`.`password` AS `password`,`oc_user`.`phone` AS `phone`,`oc_user`.`iconURL` AS `iconURL`,`oc_user`.`email` AS `email`,`oc_user`.`ipaddress` AS `ipaddress`,`oc_user`.`devicetype` AS `devicetype`,`oc_user`.`macaddress` AS `macaddress`,`oc_user`.`frozen` AS `frozen`,`oc_user`.`createtime` AS `createtime`,`oc_user`.`updatetime` AS `updatetime` from `oc_user` where (`oc_user`.`cid` = 'e7cf68e15ba3480f')"
}
]
}
},
{
"join_optimization": {//优化工作的主要阶段,包括逻辑和物理的2个阶段优化
"select#": 1,
"steps": [
{
"condition_processing": {//逻辑优化部分
"condition": "WHERE", //先看where条件,
"original_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')",
"steps": [
{
"transformation": "equality_propagation",//逻辑优化,条件优化,等式处理
"resulting_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')"
},
{
"transformation": "constant_propagation",//逻辑优化,条件优化,常量处理
"resulting_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')"
},
{
"transformation": "trivial_condition_removal",,//逻辑优化,条件简化,条件去除
"resulting_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')"
}
]
}
},
{
//这里是逻辑优化后 where条件优化结束
"substitute_generated_columns": {
}
},
{
"table_dependencies": [//逻辑优化,找出表之间的相互依赖关系,非直接可用的优化方式
{
"table": "`oc_user`",//有哪些表
"row_may_be_null": false,//是否可以不存在行数据
"map_bit": 0,//从0开始
"depends_on_map_bits": [
]
}
]
},
{
"ref_optimizer_key_uses": [//逻辑优化,找出备选的索引
{
"table": "`oc_user`",
"field": "cid", //这个是索引字段,下面的一样
"equals": "'e7cf68e15ba3480f'",
"null_rejecting": false
}
]
},
{
"rows_estimation": [//逻辑优化, 估算每个表的元组个数. 单表上进行全表扫描和索引扫描的代价估算. 每个索引都估算索引扫描代价(估算行数)
{
"table": "`oc_user`", //表名
"rows": 1,//有多少行
"cost": 1,//代价,这个值越大,花费的代价越大
"table_type": "const", //表的类型
"empty": false//是否为空
}
]
},
{
"condition_on_constant_tables": "('e7cf68e15ba3480f' = 'e7cf68e15ba3480f')",
"condition_value": true
},
{
"attaching_conditions_to_tables": {//逻辑优化,尽量吧条件绑定到对应的表上。
"original_condition": "('e7cf68e15ba3480f' = 'e7cf68e15ba3480f')",
"attached_conditions_computation": [
],
"attached_conditions_summary": [
]
}
},
{
"refine_plan": [
]
}
]
}
},
{
"join_execution": {
"select#": 1,
"steps": [
]
}
}
]
} |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set
执行器
mysql通过分析器知道了要做什么,优化器该怎么做,接下来就进入了执行器阶段,开始执行语句。 在执行语句的时候,mysql还是要坚持一下执行是否有权限,如果没有就会返回权限错误。
比如我们例子中的mytable表,字段X没有索引,那么执行器就是循环的调用InnoDb引擎接口获取表的数据,然后在对比一下是否和我们传入的值一样,如果不是就继续,是就直接存在结果集。直到取到表的最后一行数据,在把结果集返回给客户端。
到此,语句执行完毕.