MySQL 事务主要用于处理操做量大,复杂度高的数据。好比说,在一个商城系统中,用户执行购买操做,那么用户订单中应该加一条,库存要减一条,若是这两步因为意外只进行了其中一步那么就会发生很大的问题。而事务能够很好的解决这个问题。
事务是数据库处理操做,其中执行就好像它是一个单一的一组有序的工做单元。换言之在组内每一个单独的操做是成功的,那么一个事务才是完整的。若是事务中的任何操做失败,整个事务将失败。
事务性质:
-
原子性:确保工做单位中全部操做都成功完成;不然,事务被停止,在失败时会回滚到事务操做之前的状态。
-
一致性:可确保数据库在正确的更改状态进行一个成功的提交事务。
-
隔离性:使事务相互独立的操做。
-
持久性:确保了提交事务的结果或系统故障状况下仍然存在做用。
TCL(事务控制语言):
begin; 操做; commit; BEGIN或START TRANSACTION; #显式地开启一个事务 COMMIT;或COMMIT WORK; #两者等阶。COMMIT会提交事务并使已对数据库进行的全部修改为为永久性的。未COMMIT的操做都存放在内存中,仅当前客户端能够查看到,其余客户端看不到,当前客户端关闭后就清空了 ROLLBACK;或ROLLBACK WORK; #两者等阶。回滚会结束用户的事务,并撤销正在进行的全部未提交的修改 SET AUTOCOMMIT=0 #禁止自动提交 隐式开启事务 SET AUTOCOMMIT=1 #开启自动提交
事务并发的问题:mysql
1.脏读:事务A读取了事务B更新的数据,而后B回滚操做,那么A读取到的数据是脏数据sql
2.不可重复读:事务A屡次读取同一数据,事务B在事务A屡次读取过程当中,对数据做了更新并提交 ,致使事务A屡次读取同一数据时结果不一致数据库
3.幻读:系统管理员A将数据库中全部学生的成绩从具体分数改成ABCDE等级,可是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条没有改过来,就好像发生了幻觉同样缓存
各个隔离级别状况:session
#查看隔离级别 select @@session.tx_isolation; #设置隔离级别 set session transaction isolation level read uncommitted
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 |
未提交读 READ UNCOMMITED | 是 | 是 | 是 |
不可重复读 READ COMMITED | 否 | 是 | 是 |
可重复读 REPEATABLE READ | 否 | 否 | 是 |
串行化 SERIALIZABLE | 否 | 否 | 否 |
数据库锁
mysql不一样存储引擎支持不一样锁机制,innodb支持表行级锁默认行级锁,memory采用表级锁,bdb采用页面锁支持表级锁。mysql优化
表级锁:开销小,加锁快,不会出现死锁;锁定粒度大,发生锁冲突的几率最高,并发度最低。不支持事务。架构
页面锁:开销和加锁时间介于先后者之间,会出现死锁;锁定粒度介于先后者之间,并发度通常。并发
行级锁:开销大,加锁慢,会出现死锁;锁定粒度小,发生锁的冲突几率最低,并发度也最高。负载均衡
表级锁:两种模式 共享锁(读锁)与独占锁(写锁,排他锁),表级锁引擎:MyISAM MEMORY函数
- 共享锁:在读的时候上锁,全部人均可以访问不阻塞其余用户对同一表读请求,但阻塞同一表的写操做包括本身;本身若是加了读锁,更新访问其余表会提示错误;加了读锁以后不能再加写锁
- 独占锁:上锁以后其余人不能访问,阻塞其余用户对同一表的读和写操做,独占锁优先级别高于共享锁;本身加了写锁能够读写表中记录,但更新访问其余表都会提示错误
MyISAM在执行查询语句时会自动给涉及的全部表加读锁,在执行更新操做前加写锁,这个过程通常不须要用户干预。
#加锁 lock tables table_name read [local];lock tables table_name write [local]; #多表加锁 lock tables table_name [table_name] read [local];lock tables table_name [table_name] write [local]; #释放锁 unlock tables; #查询表级锁争用状况 show status like 'table%'; show status like '%lock%';当waited immediate值比较大是说明阻塞严重 show processlist; #查看哪些sql在在等待锁 show open tables; #当前被锁住的表以及锁的次数 #并发插入 myisam存储引擎有一个系统变量concurrent_insert.专门用以控制其并发插入行为,其值为NEVER0、AUTO1(默认)、ALAWAYS2。
0:不容许并发插入 ,1:若是表中没有空洞(表中没有被删除的行)myisam容许在一个进程读表的同时,另外一个进程从表尾插入记录,2:不管表中有没有空洞,都容许在表尾插入记录 #读写锁优先级 max_write_lock_count=1 #设置写锁的最屡次数,当系统处理一个写操做后就会暂停写操做给读操做执行机会 #下降写操做优先级,给读操做更高优先级 low_priority_updates=1 sql_low_priority_updates=1 在用写操做时要加low_priority关键字#视场景而定,读场景更重要或更多时如此设置
如何优化表所? concurrent_insert设置2,老是容许并发插入,可是要按期OPTIMIZE TABLE整理空间碎片;视状况设置写优先级;视状况设置写内存,解决批量插入数据(如新闻系统更新)场景中。
行级锁:引擎InnoDB,模式包含 共享锁(S),排它锁(X),意向共享锁(IS),意向排它锁(IX) 若是一个事务请求的锁模式与当前的锁兼容,innoDB就将请求的锁授予该事物;反之,若是二者不兼容,该事物就要等待锁释放
行级锁特色:innoDB行锁是经过给索引上的索引项加锁来实现的,只有经过索引条件(例如id)检索数据,innoDB才使用行级锁,佛则将使用表锁;意向锁是innoDB自动加的,不须要用户干预,对于写操做(insert update delete)innodb会自动给涉及数据加排它锁,对于select InnoDB不会加任何锁
排它锁(X) | 意向排它锁(IX) | 共享锁(S) | 意向共享锁(IS) | |
---|---|---|---|---|
排它锁(X) | 冲突 | 冲突 | 冲突 | 冲突 |
意向排它锁(IX) | 冲突 | 兼容 | 冲突 | 兼容 |
共享锁(S) | 冲突 | 冲突 | 兼容 | 兼容 |
意向共享锁(IS) | 冲突 | 兼容 | 兼容 | 兼容 |
#加锁 SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE #主动添加共享锁(S) SELECT * FROM table_name WHERE ... FOR UPDATE #主动添加独占锁(X) #释放锁 commit;或 rollback;
- 当使用行排他锁写数据时,其余人没法操做本条数据;
- 当给一条数据添加了排它锁,其余人对这条数据没有任何权限,但并不影响其余人对其余数据操做;
- 在InnoDB默认的隔离方式下,操做者不提交,操做数据只保存在内存里,另外一用户能够查询,查询到的是旧值;
- 即便字段家里索引在使用时本身变了类型,索引失效会加表锁;
间隙锁:好比有124三个数据,操做>1的数据,此时添加3或者5都是不能够的,因此要明确范围防止间隙锁
如何优化行级锁:
- 尽可能使用较低的隔离级别(新手忽略);精心设计索引,并尽可能使用索引访问数据,使加锁更精确从而减小锁冲突的机会
- 选择合理的事务大小,小事务发生锁冲突的概率也小
- 给记录集手动加锁时,最好一次性请求足够级别的锁
- 尽可能使用相等条件访问数据,这样能够避免间隙锁对并发插入的影响
- 对于一些特定事务,可使用表锁提升速度并减小死锁可能
数据库优化操做
优化成本 硬件>系统配置>数据库表结构>SQL语句及索引
优化效果 SQL语句及索引<数据库表结构<系统配置<硬件
MySQL逻辑架构:
客户端->链接线程处理->查询缓存、分析器、优化器->存储引擎
索引底层实现:B树
myisam存储是数据的地址 innodb存储的是索引值,因此索引不宜过长
explain参数详解:
select语句执行顺序:执行顺序:先where...group by ... having 再 select ... from ... 再 distinct ... order by ... limit ...
#使用方式: explain select * from demo; #参数: #id 执行顺序 id相同时顺序从被查询表数据量少至多(都同样的话按照书写顺序),子查询时id由外到里自增,先执行大的 #select_type 查询中每一个select子句的类型 SIMPLE:简单SELECT(不使用UNION或子查询) PRIMARY:最外面的SELECT UNION:UNION中的第二个或后面的SELECT语句 DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询 UNION RESULT:UNION 的结果 SUBQUERY:子查询中的第一个SELECT DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 DERIVED:派生表(FROM子句的子查询) #table 本次查询的表名,或派生表 #type mysql在表中的访问类型 ALL: 遍历全表,目标不带索引 < index: 遍历全表索引树 < range: 检索给定范围的有索引的行,between、<、>,不能用in会使索引失效 < ref: 检索给定具体值并有索引的行 < eq_ref: 检索给定具体值并是惟一索引的行 < const: 表最多有一个匹配行,它将在查询开始时被读取。由于仅有一行,在这行的列值可被优化器剩余部分认为是常数 < system: 衍生查询中只有一条数据 < NULL #possible_keys 本查询可能用的索引 #key 本查询真实用的索引 #key_len 索引在内存中占的长度(轻易不要给varchar加索引) #ref 指定的条件类型 #rows 当前语句查到的行数 #Extra Distinct:MySQL发现第1个匹配行后,中止为当前的行组合搜索更多的行。 Not exists:MySQL可以对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,再也不为前面的的行组合在该表内检查更多的行。 range checked for each record (index map: ):MySQL没有发现好的可使用的索引,但发现若是来自前面的表的列值已知,可能部分索引可使用。 Using filesort:MySQL须要额外的一次传递,以找出如何按排序顺序检索行。 Using index:从只使用索引树中的信息而不须要进一步搜索读取实际的行来检索表中的列信息,表明性能不错 Using temporary:为了解决查询,MySQL须要建立一个临时表来容纳结果。 Using where:WHERE 子句用于限制哪个行匹配下一个表或发送到客户,性能通常 Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。 Using index for group-by:相似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,能够用来查 询GROUP BY或DISTINCT查询的全部列,而不要额外搜索硬盘访问实际的表。 IMPOSSIBLE :不可能的where语句如where id=1 and id=2
mysql优化方法:
- 经过使用explain命令分析sql语句的运行效率
- 经过开启慢查询日志查看效率慢的sql语句
单多表sql优化手段:
- 给使用频繁的字段加索引,调整索引顺序最佳左前缀原则,删除多余干扰索引,调整查询条件对索引有干扰的语句放最后
多表sql额外优化手段:
- 小表驱动大表(小表在左边,where小表.x=大表.y)
- left join 给左边表加索引,right join 给右边表加索引
注意:
- 不要将索引做为函数参数或表达式的一部分,这样会让索引失效;索引不要进行类型转化不然失效
- 复合索引应该遵循最佳左前缀,不要用or,in,!= < >关键字不然失效
- 及时删除冗长,不经常使用的索引
- like查询时尽可能不要使用左边%引发索引失效
系统级别优化:
- 主从复制,读写分离,负载均衡
其余优化:
- 选尽可能小的数据类型,列设置not null,加unsigned不容许加正负这样可使正数上线多一倍,存储时间最好用TIMESTAMP使用4个字节存储,大多数状况下没有枚举类型的必要,表的列不要太不要超过10个字段多影响内存数据类型小而简单