MYSQL开发实践8问8答

chris 发表了文章 • 0 个评论 • 31 次浏览 • 1 天前 • 来自相关话题

最近研发的项目对 DB 依赖比较重,梳理了这段时间使用MySQL遇到的8个比较具有代表性的问题,答案也比较偏自己的开发实践,没有 DBA专业和深入,有出入的请使劲拍砖!
 

一、MySQL读写性能是多少,有哪些性能相关的重要参数?​

这里做了几个简单压测实验,结果如下:
机器:8核CPU,8G内存
表结构(尽量模拟业务):12个字段(1个bigint(20)为自增primary key,5个int(11),5个varchar(512),1个timestamp),InnoDB存储引擎。
实验1(写):insert => 6000/s
前提:连接数100,每次insert单条记录
分析:CPU跑了50%,这时磁盘为顺序写,故性能较高实验2(写):update(where条件命中索引) => 200/s
前提:连接数100,10w条记录,每次update单条记录的4个字段(2个int(11),2个varchar(512))
分析:CPU跑2%,瓶颈明显在IO的随机写实验3(读):select(where条件命中索引) => 5000/s
前提:连接数100,10w条记录,每次select单条记录的4个字段(2个int(11),2个varchar(512))
分析:CPU跑6%,瓶颈在IO,和db的cache大小相关实验4(读):select(where条件没命中索引) => 60/s
前提:连接数100,10w条记录,每次select单条记录的4个字段(2个int(11),2个varchar(512))
分析:CPU跑到80%,每次select都需遍历所有记录,看来索引的效果非常明显!几个重要的配置参数,可根据实际的机器和业务特点调整
max_connecttions:最大连接数

table_cache:缓存打开表的数量

key_buffer_size:索引缓存大小

query_cache_size:查询缓存大小

sort_buffer_size:排序缓存大小(会将排序完的数据缓存起来)

read_buffer_size:顺序读缓存大小

read_rnd_buffer_size:某种特定顺序读缓存大小(如order by子句的查询)PS:查看配置方法:show variables like '%max_connecttions%';
 

二、MySQL负载高时,如何找到是由哪些SQL引起的?

方法:慢查询日志分析(MySQLdumpslow)
 
慢查询日志例子,可看到每个慢查询SQL的耗时:
# User@Host: edu_online[edu_online] @ [10.139.10.167]
# Query_time: 1.958000 Lock_time: 0.000021 Rows_sent: 254786 Rows_examined: 254786
SET timestamp=1410883292;
select * from t_online_group_records;日志显示该查询用了1.958秒,返回254786行记录,一共遍历了254786行记录。及具体的时间戳和SQL语句。

使用MySQLdumpslow进行慢查询日志分析:

MySQLdumpslow -s t -t 5 slow_log_20140819.txt输出查询耗时最多的Top5条SQL语句
 
-s:排序方法,t表示按时间 (此外,c为按次数,r为按返回记录数等)
-t:去Top多少条,-t 5表示取前5条
 
执行完分析结果如下:
Count: 1076100 Time=0.09s (99065s) Lock=0.00s (76s) Rows=408.9 (440058825), edu_online[edu_online]@28hosts
select * from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > N
Count: 1076099 Time=0.05s (52340s) Lock=0.00s (91s) Rows=62.6 (67324907), edu_online[edu_online]@28hosts
select * from t_online_course where UNIX_TIMESTAMP(c_updatetime) > N
Count: 63889 Time=0.78s (49607s) Lock=0.00s (3s) Rows=0.0 (18), edu_online[edu_online]@[10x.213.1xx.1xx]
select f_uin from t_online_student_contact where f_modify_time > N
Count: 1076097 Time=0.02s (16903s) Lock=0.00s (72s) Rows=52.2 (56187090), edu_online[edu_online]@28hosts
select * from t_online_video_info where UNIX_TIMESTAMP(v_update_time) > N
Count: 330046 Time=0.02s (6822s) Lock=0.00s (45s) Rows=0.0 (2302), edu_online[edu_online]@4hosts
select uin,cid,is_canceled,unix_timestamp(end_time) as endtime,unix_timestamp(update_time) as updatetime
from t_kick_log where unix_timestamp(update_time) > N以第1条为例,表示这类SQL(N可以取很多值,这里MySQLdumpslow会归并起来)在8月19号的慢查询日志内出现了1076100次,总耗时99065秒,总返回440058825行记录,有28个客户端IP用到。

通过慢查询日志分析,就可以找到最耗时的SQL,然后进行具体的SQL分析

慢查询相关的配置参数:
log_slow_queries:是否打开慢查询日志,得先确保=ON后面才有得分析

long_query_time:查询时间大于多少秒的SQL被当做是慢查询,一般设为1S

log_queries_not_using_indexes:是否将没有使用索引的记录写入慢查询日志

slow_query_log_file:慢查询日志存放路径

三、如何针对具体的SQL做优化?

使用Explain分析SQL语句执行计划
MySQL> explain select * from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > 123456789;
+----+-------------+------------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_online_group_records | ALL | NULL | NULL | NULL | NULL | 47 | Using where |
+----+-------------+------------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)如上面例子所示,重点关注下type,rows和Extra:

type:使用类别,有无使用到索引。结果值从好到坏:... > range(使用到索引) > index > ALL(全表扫描),一般查询应达到range级别

rows:SQL执行检查的记录数

Extra:SQL执行的附加信息,如"Using index"表示查询只用到索引列,不需要去读表等

使用Profiles分析SQL语句执行时间和消耗资源:
MySQL> set profiling=1; (启动profiles,默认是没开启的)
MySQL> select count(1) from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > 123456789; (执行要分析的SQL语句)
MySQL> show profiles;
+----------+------------+----------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+----------------------------------------------------------------------------------------------+
| 1 | 0.00043250 | select count(1) from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > 123456789 |
+----------+------------+----------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
MySQL> show profile cpu,block io for query 1; (可看出SQL在各个环节的耗时和资源消耗)
+----------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
...
| optimizing | 0.000016 | 0.000000 | 0.000000 | 0 | 0 |
| statistics | 0.000020 | 0.000000 | 0.000000 | 0 | 0 |
| preparing | 0.000017 | 0.000000 | 0.000000 | 0 | 0 |
| executing | 0.000011 | 0.000000 | 0.000000 | 0 | 0 |
| Sending data | 0.000076 | 0.000000 | 0.000000 | 0 | 0 |
...
SQL优化的技巧 (只提一些业务常遇到的问题)
 
1、最关键:索引,避免全表扫描
对接触的项目进行慢查询分析,发现TOP10的基本都是忘了加索引或者索引使用不当,如索引字段上加函数导致索引失效等(如where UNIX_TIMESTAMP(gre_updatetime)>123456789)
+----------+------------+---------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+---------------------------------------+
| 1 | 0.00024700 | select * from mytable where id=100 |
| 2 | 0.27912900 | select * from mytable where id+1=101 |
+----------+------------+---------------------------------------+另外很多同学在拉取全表数据时,喜欢用select xx from xx limit 5000,1000这种形式批量拉取,其实这个SQL每次都是全表扫描,建议添加1个自增id做索引,将SQL改为 select xx from xx where id>5000 and id<6000;
+----------+------------+-----------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------------------------+
| 1 | 0.00415400 | select * from mytable where id>=90000 and id<=91000 |
| 2 | 0.10078100 | select * from mytable limit 90000,1000 |
+----------+------------+-----------------------------------------------------+合理用好索引,应该可解决大部分SQL问题。当然索引也非越多越好,过多的索引会影响写操作性能。
 
1.1 只select出需要的字段,避免select
+----------+------------+-----------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------------------------+
| 1 | 0.02948800 | select count(1) from ( select id from mytable ) a |
| 2 | 1.34369100 | select count(1) from ( select * from mytable ) a |
+----------+------------+-----------------------------------------------------+1.2 尽量早做过滤,使Join或者Union等后续操作的数据量尽量小
 
1.3 把能在逻辑层算的提到逻辑层来处理,如一些数据排序、时间函数计算等
 
PS:关于SQL优化,已经有足够多文章了,所以就不讲太全面了,只重点说自己1个感受:索引!基本都是因为索引!
 

四、SQL层面已难以优化,请求量继续增大时的应对策略?

下面是我能想到的几个方法,每个方法又都是一篇大文章了,这里就不展开。
分库分表使用集群(master-slave),读写分离增加业务的cache层使用连接池

五、MySQL如何做主从数据同步?

复制机制(Replication)
master通过复制机制,将master的写操作通过binlog传到slave生成中继日志(relaylog),slave再将中继日志redo,使得主库和从库的数据保持同步。
 
复制相关的3个MySQL线程:
slave上的I/O线程:向master请求数据master上的Binlog Dump线程:读取binlog事件并把数据发送给slave的I/O线程slave上的SQL线程:读取中继日志并执行,更新数据库
属于slave主动请求拉取的模式
 
实际使用可能遇到的问题
数据非强一致:CDB默认为异步复制,master和slave的数据会有一定延迟(称为主从同步距离,一般 < 1s)
主从同步距离变大:可能是DB写入压力大,也可能是slave机器负载高,网络波动等原因,具体问题具体分析
 
相关监控命令
show processlist:查看MySQL进程信息,包括3个同步线程的当前状态

show master status :查看master配置及当前复制信息

show slave status:查看slave配置及当前复制信息

六、如何防止DB误操作和做好容灾?

业务侧应做到的几点:
重要DB数据的手工修改操作,操作前需做到2点:1 先在测试环境操作 2 备份数据根据业务重要性做定时备份,考虑系统可承受的恢复时间进行容灾演练,感觉很必要
 
MySQL备份和恢复操作
 
1、备份:使用MySQLdump导出数据
MySQLdump -u 用户名 -p 数据库名 [表名] > 导出的文件名
MySQLdump -uxxx -p xxx mytable > mytable.20140921.bak.sql2、恢复:导入备份数据
MySQL -uxxx -p xxxx < mytable.20140921.bak.sql3、恢复:导入备份数据之后发送的写操作。先使用MySQLbinlog导出这部分写操作SQL(基于时间点或位置)
如导出2014-09-21 09:59:59之后的binlog:
MySQLbinlog --database="test" --start-date="2014-09-21 09:59:59" /var/lib/MySQL/mybinlog.000001 > binlog.data.sql如导出起始id为123456之后的binlog:
MySQLbinlog --database="test" --start-position="123456" /var/lib/MySQL/mybinlog.000001 > binlog.data.sql最后把要恢复的binlog导入db
MySQL -uxxxx -p xxxx < binlog.data.sql

七、该选择MySQL哪种存储引擎,Innodb具有什么特性?

存储引擎简介:
插件式存储引擎是MySQL的重要特性,MySQL支持多种存储引擎以满足用户的多种应用场景
存储引擎解决的问题:如何组织MySQL数据在介质中高效地读取,需考虑存储机制、索引设计、并发读写的锁机制等
MySQL5.0支持的存储引擎有MyISAM、InnoDB、Memory、Merge等
 
MyISAM和InnoDB的区别(只说重点了)
 
1. InnoDB,MySQL5.5之后及CDB的默认引擎
支持行锁:并发性能好支持事务:故InnoDB称为事务性存储引擎,支持ACID,提供了具有提交、回滚和崩溃恢复能力的事务安全支持外键:当前唯一支持外键的引擎
 
2. MyISAM,MySQL5.5之前默认引擎
支持表锁:插入+查询速度快,更新+删除速度慢不支持事务
 
使用show engines可查看当前MySQL支持的存储引擎详情:




 

八、MySQL内部结构有哪些层次?

 
非专业DBA,这里只简单贴个结构图说明下。MySQL是开源系统,其设计思路和源代码都出自大牛之手,有空可以学习下。




Connectors:连接器。接收不同语言的Client交互Management Serveices & Utilities:系统管理和控制工具Connection Pool: 连接池。管理用户连接SQL Interface: SQL接口。接受用户的SQL命令,并且返回用户需要查询的结果Parser: 解析器。验证和解析SQL语句成内部数据结构Optimizer: 查询优化器。为查询语句选择合适的执行路径Cache和Buffer:查询缓存。缓存查询的结果,有命中即可直接返回Engine:存储引擎。MySQL数据最后组织并存储成具体文件
 
作者:王昂 
原文地址:https://www.qcloud.com/community/article/233  查看全部
最近研发的项目对 DB 依赖比较重,梳理了这段时间使用MySQL遇到的8个比较具有代表性的问题,答案也比较偏自己的开发实践,没有 DBA专业和深入,有出入的请使劲拍砖!
 


一、MySQL读写性能是多少,有哪些性能相关的重要参数?​


这里做了几个简单压测实验,结果如下:
机器:8核CPU,8G内存
表结构(尽量模拟业务):12个字段(1个bigint(20)为自增primary key,5个int(11),5个varchar(512),1个timestamp),InnoDB存储引擎。
实验1(写):insert => 6000/s
前提:连接数100,每次insert单条记录
分析:CPU跑了50%,这时磁盘为顺序写,故性能较高
实验2(写):update(where条件命中索引) => 200/s
前提:连接数100,10w条记录,每次update单条记录的4个字段(2个int(11),2个varchar(512))
分析:CPU跑2%,瓶颈明显在IO的随机写
实验3(读):select(where条件命中索引) => 5000/s
前提:连接数100,10w条记录,每次select单条记录的4个字段(2个int(11),2个varchar(512))
分析:CPU跑6%,瓶颈在IO,和db的cache大小相关
实验4(读):select(where条件没命中索引) => 60/s
前提:连接数100,10w条记录,每次select单条记录的4个字段(2个int(11),2个varchar(512))
分析:CPU跑到80%,每次select都需遍历所有记录,看来索引的效果非常明显!
几个重要的配置参数,可根据实际的机器和业务特点调整
max_connecttions:最大连接数

table_cache:缓存打开表的数量

key_buffer_size:索引缓存大小

query_cache_size:查询缓存大小

sort_buffer_size:排序缓存大小(会将排序完的数据缓存起来)

read_buffer_size:顺序读缓存大小

read_rnd_buffer_size:某种特定顺序读缓存大小(如order by子句的查询)
PS:查看配置方法:show variables like '%max_connecttions%';
 


二、MySQL负载高时,如何找到是由哪些SQL引起的?


方法:慢查询日志分析(MySQLdumpslow)
 
慢查询日志例子,可看到每个慢查询SQL的耗时:
# User@Host: edu_online[edu_online] @  [10.139.10.167]
# Query_time: 1.958000 Lock_time: 0.000021 Rows_sent: 254786 Rows_examined: 254786
SET timestamp=1410883292;
select * from t_online_group_records;
日志显示该查询用了1.958秒,返回254786行记录,一共遍历了254786行记录。及具体的时间戳和SQL语句。

使用MySQLdumpslow进行慢查询日志分析:

MySQLdumpslow -s t -t 5 slow_log_20140819.txt
输出查询耗时最多的Top5条SQL语句
 
-s:排序方法,t表示按时间 (此外,c为按次数,r为按返回记录数等)
-t:去Top多少条,-t 5表示取前5条
 
执行完分析结果如下:
Count: 1076100  Time=0.09s (99065s)  Lock=0.00s (76s)  Rows=408.9 (440058825), edu_online[edu_online]@28hosts
select * from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > N
Count: 1076099 Time=0.05s (52340s) Lock=0.00s (91s) Rows=62.6 (67324907), edu_online[edu_online]@28hosts
select * from t_online_course where UNIX_TIMESTAMP(c_updatetime) > N
Count: 63889 Time=0.78s (49607s) Lock=0.00s (3s) Rows=0.0 (18), edu_online[edu_online]@[10x.213.1xx.1xx]
select f_uin from t_online_student_contact where f_modify_time > N
Count: 1076097 Time=0.02s (16903s) Lock=0.00s (72s) Rows=52.2 (56187090), edu_online[edu_online]@28hosts
select * from t_online_video_info where UNIX_TIMESTAMP(v_update_time) > N
Count: 330046 Time=0.02s (6822s) Lock=0.00s (45s) Rows=0.0 (2302), edu_online[edu_online]@4hosts
select uin,cid,is_canceled,unix_timestamp(end_time) as endtime,unix_timestamp(update_time) as updatetime
from t_kick_log where unix_timestamp(update_time) > N
以第1条为例,表示这类SQL(N可以取很多值,这里MySQLdumpslow会归并起来)在8月19号的慢查询日志内出现了1076100次,总耗时99065秒,总返回440058825行记录,有28个客户端IP用到。

通过慢查询日志分析,就可以找到最耗时的SQL,然后进行具体的SQL分析

慢查询相关的配置参数:
log_slow_queries:是否打开慢查询日志,得先确保=ON后面才有得分析

long_query_time:查询时间大于多少秒的SQL被当做是慢查询,一般设为1S

log_queries_not_using_indexes:是否将没有使用索引的记录写入慢查询日志

slow_query_log_file:慢查询日志存放路径


三、如何针对具体的SQL做优化?


使用Explain分析SQL语句执行计划
MySQL> explain select * from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > 123456789;
+----+-------------+------------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t_online_group_records | ALL | NULL | NULL | NULL | NULL | 47 | Using where |
+----+-------------+------------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
如上面例子所示,重点关注下type,rows和Extra:

type:使用类别,有无使用到索引。结果值从好到坏:... > range(使用到索引) > index > ALL(全表扫描),一般查询应达到range级别

rows:SQL执行检查的记录数

Extra:SQL执行的附加信息,如"Using index"表示查询只用到索引列,不需要去读表等

使用Profiles分析SQL语句执行时间和消耗资源:
MySQL> set profiling=1; (启动profiles,默认是没开启的)
MySQL> select count(1) from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > 123456789; (执行要分析的SQL语句)
MySQL> show profiles;
+----------+------------+----------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+----------------------------------------------------------------------------------------------+
| 1 | 0.00043250 | select count(1) from t_online_group_records where UNIX_TIMESTAMP(gre_updatetime) > 123456789 |
+----------+------------+----------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
MySQL> show profile cpu,block io for query 1; (可看出SQL在各个环节的耗时和资源消耗)
+----------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
...
| optimizing | 0.000016 | 0.000000 | 0.000000 | 0 | 0 |
| statistics | 0.000020 | 0.000000 | 0.000000 | 0 | 0 |
| preparing | 0.000017 | 0.000000 | 0.000000 | 0 | 0 |
| executing | 0.000011 | 0.000000 | 0.000000 | 0 | 0 |
| Sending data | 0.000076 | 0.000000 | 0.000000 | 0 | 0 |
...

SQL优化的技巧 (只提一些业务常遇到的问题)
 
1、最关键:索引,避免全表扫描
对接触的项目进行慢查询分析,发现TOP10的基本都是忘了加索引或者索引使用不当,如索引字段上加函数导致索引失效等(如where UNIX_TIMESTAMP(gre_updatetime)>123456789)
+----------+------------+---------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+---------------------------------------+
| 1 | 0.00024700 | select * from mytable where id=100 |
| 2 | 0.27912900 | select * from mytable where id+1=101 |
+----------+------------+---------------------------------------+
另外很多同学在拉取全表数据时,喜欢用select xx from xx limit 5000,1000这种形式批量拉取,其实这个SQL每次都是全表扫描,建议添加1个自增id做索引,将SQL改为 select xx from xx where id>5000 and id<6000;
+----------+------------+-----------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------------------------+
| 1 | 0.00415400 | select * from mytable where id>=90000 and id<=91000 |
| 2 | 0.10078100 | select * from mytable limit 90000,1000 |
+----------+------------+-----------------------------------------------------+
合理用好索引,应该可解决大部分SQL问题。当然索引也非越多越好,过多的索引会影响写操作性能。
 
1.1 只select出需要的字段,避免select
+----------+------------+-----------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------------------------+
| 1 | 0.02948800 | select count(1) from ( select id from mytable ) a |
| 2 | 1.34369100 | select count(1) from ( select * from mytable ) a |
+----------+------------+-----------------------------------------------------+
1.2 尽量早做过滤,使Join或者Union等后续操作的数据量尽量小
 
1.3 把能在逻辑层算的提到逻辑层来处理,如一些数据排序、时间函数计算等
 
PS:关于SQL优化,已经有足够多文章了,所以就不讲太全面了,只重点说自己1个感受:索引!基本都是因为索引!
 


四、SQL层面已难以优化,请求量继续增大时的应对策略?


下面是我能想到的几个方法,每个方法又都是一篇大文章了,这里就不展开。
  • 分库分表
  • 使用集群(master-slave),读写分离
  • 增加业务的cache层
  • 使用连接池


五、MySQL如何做主从数据同步?


复制机制(Replication)
master通过复制机制,将master的写操作通过binlog传到slave生成中继日志(relaylog),slave再将中继日志redo,使得主库和从库的数据保持同步。
 
复制相关的3个MySQL线程
  1. slave上的I/O线程:向master请求数据
  2. master上的Binlog Dump线程:读取binlog事件并把数据发送给slave的I/O线程
  3. slave上的SQL线程:读取中继日志并执行,更新数据库

属于slave主动请求拉取的模式
 
实际使用可能遇到的问题
数据非强一致:CDB默认为异步复制,master和slave的数据会有一定延迟(称为主从同步距离,一般 < 1s)
主从同步距离变大:可能是DB写入压力大,也可能是slave机器负载高,网络波动等原因,具体问题具体分析
 
相关监控命令
show processlist:查看MySQL进程信息,包括3个同步线程的当前状态

show master status :查看master配置及当前复制信息

show slave status:查看slave配置及当前复制信息


六、如何防止DB误操作和做好容灾?


业务侧应做到的几点:
  • 重要DB数据的手工修改操作,操作前需做到2点:1 先在测试环境操作 2 备份数据
  • 根据业务重要性做定时备份,考虑系统可承受的恢复时间
  • 进行容灾演练,感觉很必要

 
MySQL备份和恢复操作
 
1、备份:使用MySQLdump导出数据
MySQLdump -u 用户名 -p 数据库名 [表名] > 导出的文件名
MySQLdump -uxxx -p xxx mytable > mytable.20140921.bak.sql
2、恢复:导入备份数据
MySQL -uxxx -p xxxx < mytable.20140921.bak.sql
3、恢复:导入备份数据之后发送的写操作。先使用MySQLbinlog导出这部分写操作SQL(基于时间点或位置)
如导出2014-09-21 09:59:59之后的binlog:
MySQLbinlog --database="test" --start-date="2014-09-21 09:59:59" /var/lib/MySQL/mybinlog.000001 > binlog.data.sql
如导出起始id为123456之后的binlog:
MySQLbinlog --database="test" --start-position="123456" /var/lib/MySQL/mybinlog.000001 > binlog.data.sql
最后把要恢复的binlog导入db
MySQL -uxxxx -p xxxx < binlog.data.sql


七、该选择MySQL哪种存储引擎,Innodb具有什么特性?


存储引擎简介:
插件式存储引擎是MySQL的重要特性,MySQL支持多种存储引擎以满足用户的多种应用场景
存储引擎解决的问题:如何组织MySQL数据在介质中高效地读取,需考虑存储机制、索引设计、并发读写的锁机制等
MySQL5.0支持的存储引擎有MyISAM、InnoDB、Memory、Merge等
 
MyISAM和InnoDB的区别(只说重点了)
 
1. InnoDB,MySQL5.5之后及CDB的默认引擎
  • 支持行锁:并发性能好
  • 支持事务:故InnoDB称为事务性存储引擎,支持ACID,提供了具有提交、回滚和崩溃恢复能力的事务安全
  • 支持外键:当前唯一支持外键的引擎

 
2. MyISAM,MySQL5.5之前默认引擎
  • 支持表锁:插入+查询速度快,更新+删除速度慢
  • 不支持事务

 
使用show engines可查看当前MySQL支持的存储引擎详情:
engine.png

 


八、MySQL内部结构有哪些层次?


 
非专业DBA,这里只简单贴个结构图说明下。MySQL是开源系统,其设计思路和源代码都出自大牛之手,有空可以学习下。
connect.png

  1. Connectors:连接器。接收不同语言的Client交互
  2. Management Serveices & Utilities:系统管理和控制工具
  3. Connection Pool: 连接池。管理用户连接
  4. SQL Interface: SQL接口。接受用户的SQL命令,并且返回用户需要查询的结果
  5. Parser: 解析器。验证和解析SQL语句成内部数据结构
  6. Optimizer: 查询优化器。为查询语句选择合适的执行路径
  7. Cache和Buffer:查询缓存。缓存查询的结果,有命中即可直接返回
  8. Engine:存储引擎。MySQL数据最后组织并存储成具体文件

 
作者:王昂 
原文地址:https://www.qcloud.com/community/article/233 

InnoDB: Error: Table "mysql"."innodb_table_stats" not found.

采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 63 次浏览 • 2017-07-18 22:02 • 来自相关话题

MySQL之BLGC介绍

Rock 发表了文章 • 0 个评论 • 58 次浏览 • 2017-07-08 23:51 • 来自相关话题

一、组提交介绍

1.1 什么是组提交
Binary Log Group Commit 即二进制日志组提交。这是 MySQL5.6 版本中引进的一个新的特性。为什么需要引进这个特性呢?我们知道当我们把 MySQL 的 binlog 开启的时候,MySQL 会将每个事务的操作都记录到 binlog 中,方便我们使用 binlog 来完成复制或者恢复操作。可是需要调用 fsync() 才能将缓存中被更改的 binlog 真正的写到磁盘上,保证数据的持久化。但是这是一个从内存写到磁盘的过程,I/O 比较慢。如果每次事务提交都执行一遍 fsync() 将 binlog 持久化落盘到磁盘的话,效率很低。于是就想,能不能等几个事务的 binlog 一起调用一次 fsync(),一次性落盘。减少 fsync() 的次数,从而提高效率。这就是二进制日志组提交的概念。
 

二、两阶段提交

2.1 为什么需要二阶段提交
我们知道在 MySQL 中不仅仅有 binlog,还有 redo log 和 undo log 。binlog 用来记录每个事务的操作信息,redo 是在数据库宕机恢复时使用,用来恢复数据库数据,undo 用来回滚还未被提交的数据。binlog 是在数据库 Server 层产生的,即它会记录所有存储引擎中事务的操作,而 redo 是 InnoDB 存储引擎特有的日志。

在事务提交的时候,我们需要先写入二进制日志,再写 InnoDB 存储引擎的 redo。并且要求二进制日志和 redo 要么都写,要么都不写。不然可能会出现这样的情况:在主从复制的环境下,master 提交了一个事务,先写了二进制日志,但是在要写 InnoDB 存储引擎的时候,数据库发生了宕机,此时 binlog 又已经被 slave 接收到了,slave 会执行这个事务,但是实际 master 上并没有这个事务。这就会导致主从数据的不一致。所以我们引入了二阶段提交来解决这个问题,即将写 binlog 操作个 InnoDB 提交操作通过事务变成原子的。
 
2.2 什么是二阶段提交
所谓的二阶段提交就是,我在事务提交的时候,确保先将 binlog 写入,然后再到数据引擎层提交,并且这两个操作是原子的。在 MySQL 中用内部的 XA 事务来完成,即将这两个操作包装成一个事务的概念。




上图表示了二阶段提交的过程。当一个会话中的某一事务 COMMIT 的时候,进去二阶段提交的过程。首先数据库先去协调 Server 层和 Engine,询问是否都可以开始写日志,这个过程就是图中的的 prepare 阶段。协调好两层之间的关系,Server 层和 Engine 层都表示可以写日志,这时候进入下一个过程。

第二个过程就是写 binlog 的过程,先把 binlog 写到内存中,然后调用 fsync() 将 binlog 从内存写到磁盘上。

第三个过程就是在存储引擎层提交的过程,将真实修改的数据提交到数据库中。当这一步完成才最终返回给会话一个 COMMIT 成功的信号。

这整个过程就是二阶段提交的过程,如果在 fsync() 之前数据库 crash 了,重启之后数据将会被回滚,若在 fsync() 之后 crash,则会进行重做操作。通过二阶段提交的方式就保证了存储引擎与二进制日志保持一致。
 

三、三阶段提交

3.1 为什么需要三阶段提交
上面的二阶段提交是针对单一事务提交时候的操作顺序,下面我们来看看当多个事务并发的时候会是什么样的一个情况。




现在有T1、T2、T3 三个事务需要执行,从图中可以看到数据在 fsync() 之前,三个事务已经写入到了 binlog 中,通过 fsync() 操作将 binlog 刷到磁盘。之后先是 T2 COMMIT,将数据更改更新到存储引擎层,接着是 T3 COMMIT,将数据更新到存储引擎层。这时候我们做了一个热备份的操作,有多种方式进行数据库的热备份,比如:XtraBackup等。这时候就会发生错误。会发生什么错误,我们需要先了解一下 XtraBackup 等热备工具的备份原理。

XtraBackup备份原理:直接拷贝数据库文件,并且记录下当前二进制日志中已经提交的最后一个事务标记。在新的数据库实例上完成 recovery 操作。

了解完备份原理之后,我们就可以想到上述情况下做热备会出现什么情况。因为 T2、T3 已经提交,所以备份的时候会记录下 T3 是最后一个提交的事务,会认为 T3 之前的事务都是已经提交的,由于是直接拷贝数据库文件,可以看到 T1 事务的数据还没有提交到存储引擎层,所以备份数据中还并没有 T1 的数据。如果新的数据库是用来做主从复制的话,change master to 会指向二进制日志中 T3 的位置,从 T3 事务开始往后进行复制,这样一来 T1 事务的数据就这样没了。产生这个问题的主要原因就是:事务写入二进制日志的顺序与事务在存储引擎层提交的顺序不一致。

为了解决这个问题,MySQL 引入了 prepare_commit_mutext 的机制,当事务提交的时候,需要先获得 prepare_commit_mutext 这个锁。有了这个锁就可以保证事务写入二进制日志的顺序与事务在存储引擎层提交的顺序一致。




但是这样一来,从图中我们也可以看到,原先是并发的事务,又变成了串行的,效率又变低了。只要是问题,必然存在解决方法。于是三阶段提交就出现了。
 
 
3.2 什么是三阶段提交
三阶段提交,顾名思义有三个阶段: Flush 阶段、sync 阶段、commit 阶段。分别对应的就是二进制日志写内存的阶段、二进制日志刷盘的阶段、事务提交到存储引擎层的阶段。
 




每个阶段都有 leader、follower 两种角色。当一个事务进入三个阶段中的某一个阶段,如果发现这个阶段中的队列为空,那么这个事务就会成为 leader 的角色,之后进入同一阶段的事务,发现这个阶段的队列中已经有事务存在了,那就变成 follower 角色。leader 角色的任务是安排当前阶段队列中的事务按顺序执行,并且带领队列中所有的事务进入下一个阶段。当 leader 带领队列中的事务进入下一阶段的时候,如果发现下一阶段中已经有事务存在(即下一阶段已有 leader 存在),新来的 leader 自动变成 follower 角色。

三阶段提交在每个阶段都控制了事务的顺序,从而也就控制了事务执行的整体顺序。解决了 prepare_commit_mutex 锁导致的问题,事务可以并发的执行。

参考:http://blog.itpub.net/28218939/viewspace-1975809/
           http://blog.itpub.net/28218939/viewspace-1975822/
http://mysqlmusings.blogspot.jp/2012/06/binary-log-group-commit-in-mysql-56.html   查看全部


一、组提交介绍


1.1 什么是组提交
Binary Log Group Commit 即二进制日志组提交。这是 MySQL5.6 版本中引进的一个新的特性。为什么需要引进这个特性呢?我们知道当我们把 MySQL 的 binlog 开启的时候,MySQL 会将每个事务的操作都记录到 binlog 中,方便我们使用 binlog 来完成复制或者恢复操作。可是需要调用 fsync() 才能将缓存中被更改的 binlog 真正的写到磁盘上,保证数据的持久化。但是这是一个从内存写到磁盘的过程,I/O 比较慢。如果每次事务提交都执行一遍 fsync() 将 binlog 持久化落盘到磁盘的话,效率很低。于是就想,能不能等几个事务的 binlog 一起调用一次 fsync(),一次性落盘。减少 fsync() 的次数,从而提高效率。这就是二进制日志组提交的概念。
 


二、两阶段提交


2.1 为什么需要二阶段提交
我们知道在 MySQL 中不仅仅有 binlog,还有 redo log 和 undo log 。binlog 用来记录每个事务的操作信息,redo 是在数据库宕机恢复时使用,用来恢复数据库数据,undo 用来回滚还未被提交的数据。binlog 是在数据库 Server 层产生的,即它会记录所有存储引擎中事务的操作,而 redo 是 InnoDB 存储引擎特有的日志。

在事务提交的时候,我们需要先写入二进制日志,再写 InnoDB 存储引擎的 redo。并且要求二进制日志和 redo 要么都写,要么都不写。不然可能会出现这样的情况:在主从复制的环境下,master 提交了一个事务,先写了二进制日志,但是在要写 InnoDB 存储引擎的时候,数据库发生了宕机,此时 binlog 又已经被 slave 接收到了,slave 会执行这个事务,但是实际 master 上并没有这个事务。这就会导致主从数据的不一致。所以我们引入了二阶段提交来解决这个问题,即将写 binlog 操作个 InnoDB 提交操作通过事务变成原子的。
 
2.2 什么是二阶段提交
所谓的二阶段提交就是,我在事务提交的时候,确保先将 binlog 写入,然后再到数据引擎层提交,并且这两个操作是原子的。在 MySQL 中用内部的 XA 事务来完成,即将这两个操作包装成一个事务的概念。
twocommit.png

上图表示了二阶段提交的过程。当一个会话中的某一事务 COMMIT 的时候,进去二阶段提交的过程。首先数据库先去协调 Server 层和 Engine,询问是否都可以开始写日志,这个过程就是图中的的 prepare 阶段。协调好两层之间的关系,Server 层和 Engine 层都表示可以写日志,这时候进入下一个过程。

第二个过程就是写 binlog 的过程,先把 binlog 写到内存中,然后调用 fsync() 将 binlog 从内存写到磁盘上。

第三个过程就是在存储引擎层提交的过程,将真实修改的数据提交到数据库中。当这一步完成才最终返回给会话一个 COMMIT 成功的信号。

这整个过程就是二阶段提交的过程,如果在 fsync() 之前数据库 crash 了,重启之后数据将会被回滚,若在 fsync() 之后 crash,则会进行重做操作。通过二阶段提交的方式就保证了存储引擎与二进制日志保持一致
 


三、三阶段提交


3.1 为什么需要三阶段提交
上面的二阶段提交是针对单一事务提交时候的操作顺序,下面我们来看看当多个事务并发的时候会是什么样的一个情况。
t3commit.png

现在有T1、T2、T3 三个事务需要执行,从图中可以看到数据在 fsync() 之前,三个事务已经写入到了 binlog 中,通过 fsync() 操作将 binlog 刷到磁盘。之后先是 T2 COMMIT,将数据更改更新到存储引擎层,接着是 T3 COMMIT,将数据更新到存储引擎层。这时候我们做了一个热备份的操作,有多种方式进行数据库的热备份,比如:XtraBackup等。这时候就会发生错误。会发生什么错误,我们需要先了解一下 XtraBackup 等热备工具的备份原理。

XtraBackup备份原理:直接拷贝数据库文件,并且记录下当前二进制日志中已经提交的最后一个事务标记。在新的数据库实例上完成 recovery 操作。

了解完备份原理之后,我们就可以想到上述情况下做热备会出现什么情况。因为 T2、T3 已经提交,所以备份的时候会记录下 T3 是最后一个提交的事务,会认为 T3 之前的事务都是已经提交的,由于是直接拷贝数据库文件,可以看到 T1 事务的数据还没有提交到存储引擎层,所以备份数据中还并没有 T1 的数据。如果新的数据库是用来做主从复制的话,change master to 会指向二进制日志中 T3 的位置,从 T3 事务开始往后进行复制,这样一来 T1 事务的数据就这样没了。产生这个问题的主要原因就是:事务写入二进制日志的顺序与事务在存储引擎层提交的顺序不一致。

为了解决这个问题,MySQL 引入了 prepare_commit_mutext 的机制,当事务提交的时候,需要先获得 prepare_commit_mutext 这个锁。有了这个锁就可以保证事务写入二进制日志的顺序与事务在存储引擎层提交的顺序一致。
3tcommit.png

但是这样一来,从图中我们也可以看到,原先是并发的事务,又变成了串行的,效率又变低了。只要是问题,必然存在解决方法。于是三阶段提交就出现了。
 
 
3.2 什么是三阶段提交
三阶段提交,顾名思义有三个阶段: Flush 阶段、sync 阶段、commit 阶段。分别对应的就是二进制日志写内存的阶段、二进制日志刷盘的阶段、事务提交到存储引擎层的阶段。
 
3commit.png

每个阶段都有 leader、follower 两种角色。当一个事务进入三个阶段中的某一个阶段,如果发现这个阶段中的队列为空,那么这个事务就会成为 leader 的角色,之后进入同一阶段的事务,发现这个阶段的队列中已经有事务存在了,那就变成 follower 角色。leader 角色的任务是安排当前阶段队列中的事务按顺序执行,并且带领队列中所有的事务进入下一个阶段。当 leader 带领队列中的事务进入下一阶段的时候,如果发现下一阶段中已经有事务存在(即下一阶段已有 leader 存在),新来的 leader 自动变成 follower 角色。

三阶段提交在每个阶段都控制了事务的顺序,从而也就控制了事务执行的整体顺序。解决了 prepare_commit_mutex 锁导致的问题,事务可以并发的执行。


参考:http://blog.itpub.net/28218939/viewspace-1975809/
           http://blog.itpub.net/28218939/viewspace-1975822/
http://mysqlmusings.blogspot.jp/2012/06/binary-log-group-commit-in-mysql-56.html  


腾讯云正式成为MariaDB基金会白金会员

图灵之歌 发表了文章 • 0 个评论 • 139 次浏览 • 2017-06-16 16:35 • 来自相关话题

6月16日,全球开源组织MariaDB基金会宣布,腾讯云正式成为MariaDB基金会白金会员,这是基金会最高级别会员。这也是腾讯云继上个月加入CNCF基金会和Linux基金会后,在开源界的又一项新动作,意味腾讯云在开源领域的步伐正在不断深入,从IaaS的开源进入到PaaS的开源。
 


腾讯云将输出腾讯在MariaDB数据库上的经验和技术。腾讯云专家工程师程彬加入基金会成员组,成为全球仅有的7位官方成员之一。程彬负责腾讯云数据库CDB以及内核TXSQL的研发,专注于数据库和分布式存储领域相关技术和产品。他将代表腾讯云的数据库团队参加基金会每周的技术会议,提供MariaDB数据库的意见和建议,并在内部推动腾讯云MariaDB的开源进程,推动MariaDB在中国的开源工作。  
 
MariaDB基金会主席高度评价腾讯云
 
MariaDB基金会主席 Otto Kekäläinen表示:“MariaDB是未来的IT基础设施的一个基本组成部分,腾讯云在这个领域不断的思考和布局,具备锐意开创未来的主宰领导力。”他同时指出,强大的开源文化生长在中国以及亚洲,基金会的目标是将来在亚洲发起更多的活动。我们下一个MariaDB 开发者大会将在中国深圳举行。
 
MariaDB基金会官方同时评价,腾讯云的加入为基金会的发展提供强有力的资源支持,保障MariaDB开源生态的良好运转,为不断成长的用户和开发者提供服务。
 
MariaDB是由MySQL之父Michael Widenius于2009年开创的一个MySQL分支,在MySQL被商业企业收购后,为保证行业仍有开源可用的兼容MySQL的分支可用,Michael Widenius在创立了 MariaDB的同时,还成立了非赢利组织 MariaDB 基金会为MariaDB 项目、用户和开发者社区提供基础架构支持。目前MariaDB是发展最快的MySQL分支版本,新版本发布速度已经超过了商用的MySQL版本,在开源数据库领域拥有较强的技术影响力。
 
腾讯云将重点开源MariaDB内核积累
 
在腾讯内部,一直有一个数据库内核团队,在MySQL和MariaDB基础上之上做出改进优化,重点排出一些平时难以触发的bug,并在此基础上打造出了腾讯云的数据库产品。
 
在参与MySQL和MariaDB优化的过程中,腾讯云完成了主备节点锁拆分、动态调整各种级别复制参数,以及binlog写优化等;发现并解决了刷脏死锁引起的 innodb 600S crash 问题、memory barrier 引起的 hang 问题以及字符串问题等影响数据库稳定的问题。
 
未来,腾讯云还将投入更多精力到内核研发上,并会合并之前的一些内部稳定使用功能发布开源版本,尤其是适合云环境的功能的开源版本,为开源组织贡献自己的一份力量。
 
腾讯云深度拥抱全球开源生态圈
 
近年来,腾讯云大力拥抱开源事业。今年5月,腾讯云以金牌会员的身份正式加入CNCF基金会,为CNCF开源社区开放自身的Kubernetes相关特性,释放自身在容器服务、KVM虚拟化等方面的优势积累。同时基于腾讯云在Linux领域的积极贡献,腾讯云获CNCF基金会邀请加入Linux基金会。
 
此次腾讯云加入MariaDB基金会,将在数据库内核研发和功能开发方面开放助力开源,与国际的数据库专家团体建立更密切的联系,推动开放更多的技术开源。
 
未来腾讯云继续加大在开源领域的步伐,深度拥抱全球开源生态圈,从产品出发,基于大量用户在产品使用的感受和腾讯云的服务实践,将有价值的特性反馈给社区,与社区一起完善相关特性,同时从社区获得广泛的用户反馈,再次回到产品,提升腾讯云的产品体验。
 
 
延伸阅读:
腾讯云加入MariaDB基金会的官方消息:
https://mariadb.org/tencent-cloud-becomes-platinum-sponsor-mariadb-foundation/ 查看全部
6月16日,全球开源组织MariaDB基金会宣布,腾讯云正式成为MariaDB基金会白金会员,这是基金会最高级别会员。这也是腾讯云继上个月加入CNCF基金会和Linux基金会后,在开源界的又一项新动作,意味腾讯云在开源领域的步伐正在不断深入,从IaaS的开源进入到PaaS的开源。
 


腾讯云将输出腾讯在MariaDB数据库上的经验和技术。腾讯云专家工程师程彬加入基金会成员组,成为全球仅有的7位官方成员之一。程彬负责腾讯云数据库CDB以及内核TXSQL的研发,专注于数据库和分布式存储领域相关技术和产品。他将代表腾讯云的数据库团队参加基金会每周的技术会议,提供MariaDB数据库的意见和建议,并在内部推动腾讯云MariaDB的开源进程,推动MariaDB在中国的开源工作。  
 
MariaDB基金会主席高度评价腾讯云
 
MariaDB基金会主席 Otto Kekäläinen表示:“MariaDB是未来的IT基础设施的一个基本组成部分,腾讯云在这个领域不断的思考和布局,具备锐意开创未来的主宰领导力。”他同时指出,强大的开源文化生长在中国以及亚洲,基金会的目标是将来在亚洲发起更多的活动。我们下一个MariaDB 开发者大会将在中国深圳举行。
 
MariaDB基金会官方同时评价,腾讯云的加入为基金会的发展提供强有力的资源支持,保障MariaDB开源生态的良好运转,为不断成长的用户和开发者提供服务。
 
MariaDB是由MySQL之父Michael Widenius于2009年开创的一个MySQL分支,在MySQL被商业企业收购后,为保证行业仍有开源可用的兼容MySQL的分支可用,Michael Widenius在创立了 MariaDB的同时,还成立了非赢利组织 MariaDB 基金会为MariaDB 项目、用户和开发者社区提供基础架构支持。目前MariaDB是发展最快的MySQL分支版本,新版本发布速度已经超过了商用的MySQL版本,在开源数据库领域拥有较强的技术影响力。
 
腾讯云将重点开源MariaDB内核积累
 
在腾讯内部,一直有一个数据库内核团队,在MySQL和MariaDB基础上之上做出改进优化,重点排出一些平时难以触发的bug,并在此基础上打造出了腾讯云的数据库产品。
 
在参与MySQL和MariaDB优化的过程中,腾讯云完成了主备节点锁拆分、动态调整各种级别复制参数,以及binlog写优化等;发现并解决了刷脏死锁引起的 innodb 600S crash 问题、memory barrier 引起的 hang 问题以及字符串问题等影响数据库稳定的问题。
 
未来,腾讯云还将投入更多精力到内核研发上,并会合并之前的一些内部稳定使用功能发布开源版本,尤其是适合云环境的功能的开源版本,为开源组织贡献自己的一份力量。
 
腾讯云深度拥抱全球开源生态圈
 
近年来,腾讯云大力拥抱开源事业。今年5月,腾讯云以金牌会员的身份正式加入CNCF基金会,为CNCF开源社区开放自身的Kubernetes相关特性,释放自身在容器服务、KVM虚拟化等方面的优势积累。同时基于腾讯云在Linux领域的积极贡献,腾讯云获CNCF基金会邀请加入Linux基金会。
 
此次腾讯云加入MariaDB基金会,将在数据库内核研发和功能开发方面开放助力开源,与国际的数据库专家团体建立更密切的联系,推动开放更多的技术开源。
 
未来腾讯云继续加大在开源领域的步伐,深度拥抱全球开源生态圈,从产品出发,基于大量用户在产品使用的感受和腾讯云的服务实践,将有价值的特性反馈给社区,与社区一起完善相关特性,同时从社区获得广泛的用户反馈,再次回到产品,提升腾讯云的产品体验。
 
 
延伸阅读:
腾讯云加入MariaDB基金会的官方消息:
https://mariadb.org/tencent-cloud-becomes-platinum-sponsor-mariadb-foundation/

MYSQL的不同SQL模式解析

chris 发表了文章 • 0 个评论 • 192 次浏览 • 2017-05-15 23:05 • 来自相关话题

一、Mysql SQL Mode简介

通常来说MySQL服务器能够工作在不同的SQL模式下,并能针对不同的客户端以不同的方式应用这些模式。这样,应用程序就能对服务器操作进行量身定制以满足自己的需求。
 
这类模式定义了MySQL应支持的SQL语法,以及应该在数据上执行何种确认检查。这样,就能在众多不同的环境下、与其他数据库服务器一起更容易地使用MySQL。
 
可以使用" --sql-mode="modes" "选项,通过启动mysqld来设置默认的SQL模式。而从MySQL 4.1开始,也能在启动之后,使用SET [SESSION|GLOBAL] sql_mode='modes'语句,通过设置sql_mode变量更改其模式。
 
通常在linux下安装完mysql后,其默认的sql-mode值是空,在这种情形下mysql执行的是一种不严格的检查,例如日期字段可以插入'0000-00-00 00:00:00'这样的值,还有如果要插入的字段长度超过列定义的长度,那么mysql不会终止操作,而是会自动截断后面的字符继续插入操作,如下例:
mysql> create table t1 (c1 char(3));
mysql> insert into t1 values('abcd');
mysql> select * from t1;
+------+
| c1 |
+------+
| abc |
+------+
1 row in set (0.00 sec)我们发现插入的字符被自动截断了,但是如果我们本意希望如果长度超过限制就报错,那么我们可以设置sql_mode为STRICT_TRANS_TABLES,如下:
mysql> set session sql_mode='STRICT_TRANS_TABLES'这样我们再执行同样的操作,mysql就会告诉我们插入的值太长,操作被终止,如下:
mysql> insert into t1 values('abcd');
ERROR 1406 (22001): Data too long for column 'c1' at row 1
经常使用的sql_mode值:




说明:如果把sql_mode的值设置成后面的两个值(也就是我们说的严格模式),那么当在列中插入或更新不正确的值时,mysql将会给出错误,并且放弃insert/update操作。
 
在我们的一般应用中建议使用这两种模式,而不是使用默认的空或ANSI模式。但是需要注意的问题是,如果数据库运行在严格模式下,并且你的存储引擎不支持事务,那么有数据不一致的风险存在,比如一组sql中有两个dml语句,如果后面的一个出现了问题,但是前面的已经操作成功,那么mysql并不能回滚前面的操作。因此说设置sql_mode需要应用人员权衡各种得失,从而得到一个合适的选择。
 
Sql_mode的值还有很多,这里不再累述,可以参考相关的手册。
 
 

二、SQL Mode与可移植性

如果mysql与其它异构数据库之间有数据移植的需求的话,那么下面的sql_mode的组合设置可以达到相应的效果:




 

三、SQL Mode与数据效验

SQL Mode 还可以实现对数据效验和转移等功能如: 
效验日期数据合法性. 在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误 将‘"'视为识别符引号(‘`'引号字符) 禁用反斜线字符(‘\')做为字符串内的退出字符。启用NO_BACKSLASH_ESCAPES模式,反斜线则成为普通字符。 将||视为字符串连接操作符(+)(同CONCAT()),而不视为OR。 查看全部


一、Mysql SQL Mode简介


通常来说MySQL服务器能够工作在不同的SQL模式下,并能针对不同的客户端以不同的方式应用这些模式。这样,应用程序就能对服务器操作进行量身定制以满足自己的需求。
 
这类模式定义了MySQL应支持的SQL语法,以及应该在数据上执行何种确认检查。这样,就能在众多不同的环境下、与其他数据库服务器一起更容易地使用MySQL。
 
可以使用" --sql-mode="modes" "选项,通过启动mysqld来设置默认的SQL模式。而从MySQL 4.1开始,也能在启动之后,使用SET [SESSION|GLOBAL] sql_mode='modes'语句,通过设置sql_mode变量更改其模式。
 
通常在linux下安装完mysql后,其默认的sql-mode值是空,在这种情形下mysql执行的是一种不严格的检查,例如日期字段可以插入'0000-00-00 00:00:00'这样的值,还有如果要插入的字段长度超过列定义的长度,那么mysql不会终止操作,而是会自动截断后面的字符继续插入操作,如下例:
mysql> create table t1 (c1 char(3));
mysql> insert into t1 values('abcd');
mysql> select * from t1;
+------+
| c1 |
+------+
| abc |
+------+
1 row in set (0.00 sec)
我们发现插入的字符被自动截断了,但是如果我们本意希望如果长度超过限制就报错,那么我们可以设置sql_mode为STRICT_TRANS_TABLES,如下:
mysql> set session sql_mode='STRICT_TRANS_TABLES'
这样我们再执行同样的操作,mysql就会告诉我们插入的值太长,操作被终止,如下:
mysql> insert into t1 values('abcd');
ERROR 1406 (22001): Data too long for column 'c1' at row 1

经常使用的sql_mode值:
sqlmode.png

说明:如果把sql_mode的值设置成后面的两个值(也就是我们说的严格模式),那么当在列中插入或更新不正确的值时,mysql将会给出错误,并且放弃insert/update操作。
 
在我们的一般应用中建议使用这两种模式,而不是使用默认的空或ANSI模式。但是需要注意的问题是,如果数据库运行在严格模式下,并且你的存储引擎不支持事务,那么有数据不一致的风险存在,比如一组sql中有两个dml语句,如果后面的一个出现了问题,但是前面的已经操作成功,那么mysql并不能回滚前面的操作。因此说设置sql_mode需要应用人员权衡各种得失,从而得到一个合适的选择。
 
Sql_mode的值还有很多,这里不再累述,可以参考相关的手册。
 
 


二、SQL Mode与可移植性


如果mysql与其它异构数据库之间有数据移植的需求的话,那么下面的sql_mode的组合设置可以达到相应的效果:
databaseclass.png

 


三、SQL Mode与数据效验


SQL Mode 还可以实现对数据效验和转移等功能如: 
  1. 效验日期数据合法性. 
  2. 在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误 
  3. 将‘"'视为识别符引号(‘`'引号字符) 
  4. 禁用反斜线字符(‘\')做为字符串内的退出字符。启用NO_BACKSLASH_ESCAPES模式,反斜线则成为普通字符。 
  5. 将||视为字符串连接操作符(+)(同CONCAT()),而不视为OR。

MYSQL大小写敏感介绍

chris 发表了文章 • 0 个评论 • 196 次浏览 • 2017-05-08 22:55 • 来自相关话题

简介

在MySQL中,数据库对应数据目录中的目录。数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎)。因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性。
 
在大多数Unix中数据库名和表名对大小写敏感,而在Windows中对大小写不敏感。一个显著的例外情况是Mac OS X,它基于Unix但使用默认文件系统类型(HFS+),对大小写不敏感。然而,Mac OS X也支持UFS卷,该卷对大小写敏感,就像Unix一样。
 
变量lower_case_file_system说明是否数据目录所在的文件系统对文件名的大小写敏感。ON说明对文件名的大小写不敏感,OFF表示敏感。
 
例如在Linux下查看:
mysql> show variables like 'lower%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| lower_case_file_system | OFF |
| lower_case_table_names | 0 |
+------------------------+-------+
2 rows in set (0.00 sec)说明Linux系统对大小写敏感,MySQL也默认设置为对大小写敏感, 而Windows则相反。
 

大小写区分规则

Linux下:
数据库名与表名是严格区分大小写的;表的别名是严格区分大小写的;列名与列的别名在所有的情况下均是忽略大小写的;变量名也是严格区分大小写的;
 
windows下:
都不区分大小写
 
Mac OS下(非UFS卷):
都不区分大小写
 

参数说明

unix下lower_case_table_names默认值为 0 ;  Windows下默认值是 1 ;Mac OS X下默认值是 2 .





由大小写敏感转换为不敏感方法

如果原来所建立库及表都是对大小写敏感的,想要转换为对大小写不敏感,主要需要进行如下3步:
将数据库数据通过mysqldump导出。在my.cnf中更改lower_case_tables_name = 1,并重启mysql数据库。将导出的数据导入mysql数据库。
 

注意事项

为了避免大小写引发的问题,一种推荐的命名规则是:在定义数据库、表、列的时候全部采用小写字母加下划线的方式,不使用任何大写字母
 
在任何系统中可以使用lower_case_tables_name=1。使用该选项的不利之处是当使用SHOW TABLES或SHOW DATABASES时,看不出名字原来是用大写还是小写。
 
请注意在Unix中如果以前lower_case_tables_name = 0将lower_case_tables_name设置为1之前,重启mysqld之前,必须先将旧的数据库名和表名转换为小写。 查看全部


简介


在MySQL中,数据库对应数据目录中的目录。数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎)。因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性。
 
在大多数Unix中数据库名和表名对大小写敏感,而在Windows中对大小写不敏感。一个显著的例外情况是Mac OS X,它基于Unix但使用默认文件系统类型(HFS+),对大小写不敏感。然而,Mac OS X也支持UFS卷,该卷对大小写敏感,就像Unix一样。
 
变量lower_case_file_system说明是否数据目录所在的文件系统对文件名的大小写敏感。ON说明对文件名的大小写不敏感,OFF表示敏感。
 
例如在Linux下查看:
mysql> show variables like 'lower%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| lower_case_file_system | OFF |
| lower_case_table_names | 0 |
+------------------------+-------+
2 rows in set (0.00 sec)
说明Linux系统对大小写敏感,MySQL也默认设置为对大小写敏感, 而Windows则相反。
 


大小写区分规则


Linux下
  • 数据库名与表名是严格区分大小写的;
  • 表的别名是严格区分大小写的;
  • 列名与列的别名在所有的情况下均是忽略大小写的;
  • 变量名也是严格区分大小写的;

 
windows下
  • 都不区分大小写

 
Mac OS下(非UFS卷):
  • 都不区分大小写

 


参数说明


unix下lower_case_table_names默认值为 0 ;  Windows下默认值是 1 ;Mac OS X下默认值是 2 .
args.png


由大小写敏感转换为不敏感方法


如果原来所建立库及表都是对大小写敏感的,想要转换为对大小写不敏感,主要需要进行如下3步:
  1. 将数据库数据通过mysqldump导出。
  2. 在my.cnf中更改lower_case_tables_name = 1,并重启mysql数据库。
  3. 将导出的数据导入mysql数据库。

 


注意事项


为了避免大小写引发的问题,一种推荐的命名规则是:在定义数据库、表、列的时候全部采用小写字母加下划线的方式,不使用任何大写字母
 
在任何系统中可以使用lower_case_tables_name=1。使用该选项的不利之处是当使用SHOW TABLES或SHOW DATABASES时,看不出名字原来是用大写还是小写。
 
请注意在Unix中如果以前lower_case_tables_name = 0将lower_case_tables_name设置为1之前,重启mysqld之前,必须先将旧的数据库名和表名转换为小写。

MYSQL不同库质检查询

采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 274 次浏览 • 2017-03-20 11:49 • 来自相关话题

关于haproxy、mycat、mysql的问题

采菊篱下 回复了问题 • 2 人关注 • 1 个回复 • 349 次浏览 • 2017-03-13 15:16 • 来自相关话题

编译cmake MySQL 5.6.10报错

Nock 回复了问题 • 2 人关注 • 1 个回复 • 447 次浏览 • 2017-03-10 16:03 • 来自相关话题

MYSQL的八大缺陷

小白菜 发表了文章 • 0 个评论 • 415 次浏览 • 2016-12-29 11:39 • 来自相关话题

MySQL体积小,速度快,功能丰富,总体拥有成本低。它还是一个开源的关联式数据库管理系统,它的伟大成就说明了一个成功的公司是可以建立在开源之上的。
 
虽然用过mysql的人都曾对其出现的问题而抓狂,但只要是机器,总避免不了出问题的,更何况是一种每秒能保存成千上万行互联网数据,你怎么保证它一点错误都没有呢?
 
以下列举了8个开源关系型数据库的缺陷,其中不仅限于MySQL,还有是针对关系型数据库的。只有明白了关系型数据库和MySQL,才能更好地避免在使用MySQL中尽量少地遇到一些意外。
 

1、无法避免的bugs

任何一个软件包都有bug。但稍微深入了解一下,就会发现和Mysql相关的bugs自成体系。突然你就需要留心,因为NULL并不是以同样的方式出现,外键约束也没有像你想像的那样执行,连主键自动增长也会出错。

到处都避免不了小问题,而且并不总是可以修复的,这就是为什么一些人保持一个列表。还好MySQL维护着一个非常好的bug报告系统,让我们可以知道我些我们无法想像的事情,知道其他人也在经受同样的磨难。
 

2、关系表的不灵活性

关系表具有条理性是好的,但这迫使程序员要编造或把一些数据塞到已经定义好模式的列中。NoSQL之所以越来越受欢迎,其中一个原因就是它为程序员提供了足够的灵活性,以加速数据库的使用。如果一个街道地址需要增加一行,那么,你可以将它很容易地插入到一个NoSQL文档中。如果你想添加一个完整的新的数据块,无论它包含什么内容,文档模型也可以原封不动地接受你的数据,而不必改为它要求的数据格式。

假设你用整数格式建立了一个全部是邮编的表格。这个表十分高效,执行规则也很好。可是有一次,有人上传了一个使用了连字符的九位数邮编。或者说你得到了一位来自他国的客户的信件,上面写有邮政编码。这时,你会感到一切都乱了。老板要求网站要在几小时内恢复正常工作。然而,你已经没有时间重建数据库。程序员可以做什么?使用黑客手段把这位客户的邮政编码由base 64的数字格式改为base 10格式?或者设置一个使用转义编码的辅助表格,用来说明真正的邮政编码或者其他?危险的黑客无处不在,但你没有时间来搞定它。

MySQL的关联规则让每个人都诚实和谨慎,但它能强制我们避开易受攻击和欺骗的麻烦。
 

3、存储引擎混乱

总体来说,Mysql的存储引擎接口定义还算良好的。MySQL不是实际上的同一的数据库。它是由几个数据库组成,它们的大多数细节都被统一的表面掩盖了。开始时有一个MyISAM引擎,它很快但在前后一致上不能做到完备。有时你需要速度并且可以接受不一致的结果时是很好的。

当人们需要更多时,具备完整事务支持的Inno DB出现了。但这还不够。现在,它可能有20种存储引擎的选择——这足以使一个数据库管理员疯狂。当然,有时在不同的存储引擎之间切换而不必重写你的SQL是很好的,但是切换后总会带来混乱。这个表格我选择的引擎是MyISAM还是innoDB呢?或者,我决定输出的数据是CSV格式的吗?
 

4、JOIN联合查询

曾经,将数据分表保存是计算机科学史上的伟大创新。分开后的表不仅结构简单,使用上也简化了许多。但它却需要使用join语句来进行查询。

sql通过一系列join构建的复杂查询将开发者推入了困惑与绝望的深渊。而且存储引擎也需要以最优的方式来高效地解析join语句。开发者需要绞尽脑汁编写查询语句,然后数据库对其进行解析。

这就是很多注重运行速度的开发者放弃数据分表转而使用不规范数据表的原因。不区分数据实体,将所有数据保存到一个大表中——以避免复杂的查询。这样确实很快,并且服务器也不会耗尽内存。

现在的磁盘空间很廉价。8TB的磁盘已经在售,更大容量的也将上市。我们不再需要为使用join而绞尽脑汁了。
 

5、分支的混乱

毋庸置疑,一个可靠的、得到良好支持的MySQL分支,可以带来竞争和选择,但是它也引起困惑和混乱。更糟糕的是,一个称为MariaDB的MySQL分支,由Monty Widenius维护着。他同样也在参与编写MySQL。那么,Maria DB是真正独立的值得我们拥护的吗?或者它是MySQL?我们是否应该坚持使用由创建原始mysql数据库的组织运营的核心代码?或者我们应该加入那些被认为更聪明的,往往很酷的背叛者?

如何获取关于兼容性的信息?虽然Maria DB和MySQL十分相似,但它们之间也有差异。这就是大家一直都在争论它的原因。在性能方面,在我们查询的范围内,在两个阵营中,也许它们的工作方式相同,但也许不同,也许将来会不同。
 

6、开发MySQL的动机

虽然MySQL是一款成功的开源产品,但它仍属于商业中的一款产品,专业开发者需要靠它来获得利益,当然,最直接的利益就是薪资。当大多数用户在持续地享受开源许可证带来的最佳体验时,毫无疑问这家公司还在为赚取足够的钱来维持运营而努力。这导致自由代码在“社区版”和出售给企业的完整产品之间产生了奇怪的分岐。

我们应该对这款产品付钱吗?这种在社区版开展经营的行为是否公平?企业版中额外的功能是不是一个噱头,以引诱我们不断付费的呢?这至少说明一点,它是另一些需要回答的问题:选用哪个版本?遵照哪种许可证?选用它的哪个功能集?
 

7、原生JSON支持的缺乏

通过安装MySQL查看其年龄,然后你就知道需要添加哪些驱动程序使它变得可用。MySQL通常在3306端口上通信,一般输出的是它本身难以理解的格式化数据。如果要让你的代码和它通信,你必须添加另一层代码,将MySQL的语言转换成有用的东西。这些层的代码,以库的形式分发,经常需要人们购买一个商业许可证。

现代数据存储层通常直接以JSON通信。虽然MySQL和Maria DB现在有能力解析SQL中的JSON部分,但这还远远不够,原生的JSON接口已经被广泛使用于CouchDB、MongoDB,或任何最新的工具中。
 

8、封闭源和专有模块的兴起

虽然MySQL是开源的,但除了一些在”开源核心“周边开发的一些较新的、非开源的代码和专有模块。程序员也需要赚钱、需要生活,Oracle需要拿它的辛苦成果来换钱,这是一种现实,也是商业的性质。使用MySQL你也不可以免费得到任何东西。

要求MySQL始终坚持在一个很高的标准上,这有点不公平,因为开源的成功可能是一个圈套。它开始可以免费,但并不意味着它可以始终免费。如果企业需要更多新的功能,他们就要通过各种方式付费来获取。有时向Oracle付费,比自己来编写代码要便宜得多。有时商业的、不开源的代码是有意义的。

MySQL虽然作为一个成功的开源系统,但以上这些问题也总不可避免地出现,这就需要我们在它们发生之前有个深刻的认识,才能在今后的应用中避免不必要的麻烦。 查看全部
MYSQL.png

MySQL体积小,速度快,功能丰富,总体拥有成本低。它还是一个开源的关联式数据库管理系统,它的伟大成就说明了一个成功的公司是可以建立在开源之上的。
 
虽然用过mysql的人都曾对其出现的问题而抓狂,但只要是机器,总避免不了出问题的,更何况是一种每秒能保存成千上万行互联网数据,你怎么保证它一点错误都没有呢?
 
以下列举了8个开源关系型数据库的缺陷,其中不仅限于MySQL,还有是针对关系型数据库的。只有明白了关系型数据库和MySQL,才能更好地避免在使用MySQL中尽量少地遇到一些意外。
 


1、无法避免的bugs


任何一个软件包都有bug。但稍微深入了解一下,就会发现和Mysql相关的bugs自成体系。突然你就需要留心,因为NULL并不是以同样的方式出现,外键约束也没有像你想像的那样执行,连主键自动增长也会出错。

到处都避免不了小问题,而且并不总是可以修复的,这就是为什么一些人保持一个列表。还好MySQL维护着一个非常好的bug报告系统,让我们可以知道我些我们无法想像的事情,知道其他人也在经受同样的磨难。
 


2、关系表的不灵活性


关系表具有条理性是好的,但这迫使程序员要编造或把一些数据塞到已经定义好模式的列中。NoSQL之所以越来越受欢迎,其中一个原因就是它为程序员提供了足够的灵活性,以加速数据库的使用。如果一个街道地址需要增加一行,那么,你可以将它很容易地插入到一个NoSQL文档中。如果你想添加一个完整的新的数据块,无论它包含什么内容,文档模型也可以原封不动地接受你的数据,而不必改为它要求的数据格式。

假设你用整数格式建立了一个全部是邮编的表格。这个表十分高效,执行规则也很好。可是有一次,有人上传了一个使用了连字符的九位数邮编。或者说你得到了一位来自他国的客户的信件,上面写有邮政编码。这时,你会感到一切都乱了。老板要求网站要在几小时内恢复正常工作。然而,你已经没有时间重建数据库。程序员可以做什么?使用黑客手段把这位客户的邮政编码由base 64的数字格式改为base 10格式?或者设置一个使用转义编码的辅助表格,用来说明真正的邮政编码或者其他?危险的黑客无处不在,但你没有时间来搞定它。

MySQL的关联规则让每个人都诚实和谨慎,但它能强制我们避开易受攻击和欺骗的麻烦。
 


3、存储引擎混乱


总体来说,Mysql的存储引擎接口定义还算良好的。MySQL不是实际上的同一的数据库。它是由几个数据库组成,它们的大多数细节都被统一的表面掩盖了。开始时有一个MyISAM引擎,它很快但在前后一致上不能做到完备。有时你需要速度并且可以接受不一致的结果时是很好的。

当人们需要更多时,具备完整事务支持的Inno DB出现了。但这还不够。现在,它可能有20种存储引擎的选择——这足以使一个数据库管理员疯狂。当然,有时在不同的存储引擎之间切换而不必重写你的SQL是很好的,但是切换后总会带来混乱。这个表格我选择的引擎是MyISAM还是innoDB呢?或者,我决定输出的数据是CSV格式的吗?
 


4、JOIN联合查询


曾经,将数据分表保存是计算机科学史上的伟大创新。分开后的表不仅结构简单,使用上也简化了许多。但它却需要使用join语句来进行查询。

sql通过一系列join构建的复杂查询将开发者推入了困惑与绝望的深渊。而且存储引擎也需要以最优的方式来高效地解析join语句。开发者需要绞尽脑汁编写查询语句,然后数据库对其进行解析。

这就是很多注重运行速度的开发者放弃数据分表转而使用不规范数据表的原因。不区分数据实体,将所有数据保存到一个大表中——以避免复杂的查询。这样确实很快,并且服务器也不会耗尽内存。

现在的磁盘空间很廉价。8TB的磁盘已经在售,更大容量的也将上市。我们不再需要为使用join而绞尽脑汁了。
 


5、分支的混乱


毋庸置疑,一个可靠的、得到良好支持的MySQL分支,可以带来竞争和选择,但是它也引起困惑和混乱。更糟糕的是,一个称为MariaDB的MySQL分支,由Monty Widenius维护着。他同样也在参与编写MySQL。那么,Maria DB是真正独立的值得我们拥护的吗?或者它是MySQL?我们是否应该坚持使用由创建原始mysql数据库的组织运营的核心代码?或者我们应该加入那些被认为更聪明的,往往很酷的背叛者?

如何获取关于兼容性的信息?虽然Maria DB和MySQL十分相似,但它们之间也有差异。这就是大家一直都在争论它的原因。在性能方面,在我们查询的范围内,在两个阵营中,也许它们的工作方式相同,但也许不同,也许将来会不同。
 


6、开发MySQL的动机


虽然MySQL是一款成功的开源产品,但它仍属于商业中的一款产品,专业开发者需要靠它来获得利益,当然,最直接的利益就是薪资。当大多数用户在持续地享受开源许可证带来的最佳体验时,毫无疑问这家公司还在为赚取足够的钱来维持运营而努力。这导致自由代码在“社区版”和出售给企业的完整产品之间产生了奇怪的分岐。

我们应该对这款产品付钱吗?这种在社区版开展经营的行为是否公平?企业版中额外的功能是不是一个噱头,以引诱我们不断付费的呢?这至少说明一点,它是另一些需要回答的问题:选用哪个版本?遵照哪种许可证?选用它的哪个功能集?
 


7、原生JSON支持的缺乏


通过安装MySQL查看其年龄,然后你就知道需要添加哪些驱动程序使它变得可用。MySQL通常在3306端口上通信,一般输出的是它本身难以理解的格式化数据。如果要让你的代码和它通信,你必须添加另一层代码,将MySQL的语言转换成有用的东西。这些层的代码,以库的形式分发,经常需要人们购买一个商业许可证。

现代数据存储层通常直接以JSON通信。虽然MySQL和Maria DB现在有能力解析SQL中的JSON部分,但这还远远不够,原生的JSON接口已经被广泛使用于CouchDB、MongoDB,或任何最新的工具中。
 


8、封闭源和专有模块的兴起


虽然MySQL是开源的,但除了一些在”开源核心“周边开发的一些较新的、非开源的代码和专有模块。程序员也需要赚钱、需要生活,Oracle需要拿它的辛苦成果来换钱,这是一种现实,也是商业的性质。使用MySQL你也不可以免费得到任何东西。

要求MySQL始终坚持在一个很高的标准上,这有点不公平,因为开源的成功可能是一个圈套。它开始可以免费,但并不意味着它可以始终免费。如果企业需要更多新的功能,他们就要通过各种方式付费来获取。有时向Oracle付费,比自己来编写代码要便宜得多。有时商业的、不开源的代码是有意义的。

MySQL虽然作为一个成功的开源系统,但以上这些问题也总不可避免地出现,这就需要我们在它们发生之前有个深刻的认识,才能在今后的应用中避免不必要的麻烦。