SQL优化:
最大化使用索引。
避免使用not in ,尽量使用not exists。
避免使用or,可以用union 代替。
避免使用null值判断,会导致数据库引擎放弃索引进行全表扫描。(字段添加默认值0)
避免在where条件中左侧进行表达式、函数操作。可以放在等号右边。(这样函数只会作用在结果集上,不是全部)
数据量大时,避免使用where 1=1。(会进行全表扫描)
order by字段尽量与where条件中字段一样。(这样可以利用索引排序)
多表关联时,小表在前,大表在后。(第一张表涉及全表扫描)。
不建议使用自查询,用inner代替。
索引字段在where条件后面不能运算,否则索引失效。
order by后面的列由索引,索引可以消除排序带来的cpu开销,如果是前缀索引,是不能消除排序的。
gorup_concat是字符串聚合函数,慎用!!!会影响sql响应时间。如果返回值过大超过了max_allowed_packet 设置会导致程序报错!
Text类型字段,消耗大量的网络和IO带宽。由于返回值超过max_allowed_packet设置会导致程序报错。
Like尽量不用“%…%”.
Like模糊查询,开头用%,会使用不到索引。这种情况给字段加上reverse()函数,即可用上索引。案例: where reverse(object_name)like reverse(‘%AS’);
Mysql隔离级别
innodb和myISAM区别:
InnoDB支持外键,MyISAM不支持
InnoDB支持事务,MyISAM不支持
COUNT()在 MyISAM 表中会非常快,而在InnoDB 表下可能会很痛苦
主键查询在InnoDB下相当快,但如果主键太长了也会导致性能问题
场景: MyISAM适合select以及insert为主的应用,InnoDB适合频繁update以及涉及到安全性较高的应用
事务是指一组数据的操作,事务内操作要不全部成功,要不全部失败。
事务特性:
原子性:指事务的原子性操,数据的修改要么全部执行成功,要么全部失败,实现事务的原子性,是基于日志的Redo/Undo机制。
一致性:指执行事务前后的状态要一致,可以理解为数据一致性。
隔离性:指事务之间相互隔离,不受影响。
持久性:在一个事务提交后,这个事务的状态会被持久化到数据库中
原子性、隔离性、持久性都是为了保障一致性而存在的,一致性也是最终的目的。
redo/undo机制:将所有对数据的更新操作写到日志中。
隔离级别实际解决的问题:
脏读:读到了其他事务未提交的数据,未提交的数据可能会回滚,也就是不存在的数据。
可重复读:在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的。通常针对Update操作。
不可重复读:在一个事务内不同的时刻读到的同一批数据不一致,可能会收到其他事务的影响,比如其他事务修改了数据并提交了。通常针对Update操作。
幻读:用户读取某一范围的数据行时,另一个事务在这个范围插入新行,当用户再次读取这个范围数据行时,会读到新的行。mysql通过多版本并发控制MVVC机制解决了问题。
幻读案例:
第一个事务查询一个User表id=100发现不存在该数据行,这时第二个事务又进来了,新增了一条id=100的数据行并且提交了事务。
这时第一个事务新增一条id=100的数据行会报主键冲突,第一个事务再select一下,发现id=100数据行已经存在,这就是幻读。
四种隔离级别:
事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 是 是 是
不可重复读(read-committed) 否 是 是
可重复读(repeatable-read) 否 否 是
串行化(serializable) 否 否 否
MYSQL事务在innodb引擎下,MyISAM引擎下不支持事务。
查看隔离级别:show variables like ‘%isolation%’;
修改隔离级别:set tx_isolation=‘READ-UNCOMMITTED’;
读未提交:任何事务对数据的修改都暴露给其他事务。即使事务还没提交。
读提交:是只能读到其他事务已提交的数据。
可重复读:确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。会导致幻读问题。
串行化:隔离效果最好的,它是在每个读的数据行上加上共享锁,此时不可写数据;写的时候加排他锁,阻塞其他事务写入或读取;在这个级别,可能导致大量的超时现象和锁竞争。
Mysql隔离级别是靠加锁来实现的:
共享锁/读锁、排他锁/写锁、间隙锁、行锁、表锁。
共享锁 是针对同一份数据,多个读操作可以同时进行,简单来说即读加锁,不能写并且可并行读。
排他锁 针对写操作,假如当前写操作没有完成,那么它会阻断其它的写锁和读锁,即写加锁,其它读写都阻塞 。
行锁 锁当前数据行,锁粒度小,加锁慢,发生锁冲突概率小,并发高。InnoDB支持行锁 。
表锁 锁的粒度大,加锁快,开销小,但是锁冲突的概率大,并发度低。
间隙锁 Gap Locks和Next-Key Locks
Gap Locks会锁住两个索引之间的区间。例如:
select * from User where id>3 and id<5 for update,就会在区间(3,5)之间加上Gap Locks。
Next-Key Locks是Gap Locks+Record Locks形成闭区间锁。
select * from User where id>=3 and id=<5 for update,就会在区间[3,5]之间加上Next-KeysLocks。
在数据库的增、删、改、查中,只有增、删、改才会加上排它锁。
只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
MVCC机制:
在实现MVCC时用到了一致性视图,用于支持读提交和可重复读的实现。
在实现可重复读的隔离级别,只需要在事务开始的时候创建一致性视图,也叫做快照,之后的查询里都共用这个一致性视图,后续的事务对数据的更改是对当前事务是不可见的,这样就实现了可重复读。
在实现读提交,每一个语句执行前都会重新计算出一个新的视图,这个也是可重复读和读提交在MVCC实现层面上的区别。
快照(视图)在MVCC底层是怎么工作?
在InnoDB 中每一个事务都有一个自己的唯一、递增事务id 。
对于Mysql中的每一个数据行都有可能存在多个版本,在每次事务更新数据的时候,都会生成一个新的数据版本,并且把自己的数据id赋值给当前版本的row trx_id。
图示:
如图中所示,假如三个事务更新了同一行数据,那么就会有对应的三个数据版本。
实际上版本1、版本2并非实际物理存在的,而图中的U1和U2实际就是undo log,这v1和v2版本是根据当前v3和undo log计算出来的。
对于一个快照来说,它要遵循什么规则?
对于一个事务视图来说除了对自己更新的总是可见,另外还有三种情况:版本未提交的,都是不可见的;版本已经提交,但是是在创建视图之后提交的也是不可见的;版本已经提交,若是在创建视图之前提交的是可见的。
假如两个事务执行写操作,又怎么保证并发?
update的where后的条件是在有索引的情况下:
假如事务1和事务2都要执行update操作,事务1先update数据行的时候,先回获取行锁,锁定数据,当事务2要进行update操作的时候,也会取获取该数据行的行锁,但是已经被事务1占有,事务2只能wait。
若是事务1长时间没有释放锁,事务2就会出现超时异常 。
没有索引的条件下:
若是没有索引的条件下,就获取所有行,都加上行锁,然后Mysql会再次过滤符合条件的的行并释放锁,只有符合条件的行才会继续持有锁。
这样的性能消耗也会比较大。
创建索引:create index indexName on tableName (columnName);
存储过程:
DELIMITER $ --声明存储过程的结束符
CREATE PROCEDURE stu_test() --存储过程名称(参数列表)
BEGIN --开始
-- 可以写多个sql语句 -- sql语句+流程控制
END $ --结束 结束符
-- 执行存储过程
call stu_test() --call 存储过程名称(参数)
参数:
IN: 表示输入参数,可以携带数据带存储过程中
OUT: 表示输出参数,可以从存储过程中返回结果
INOUT: 表示输入输出参数,两者结合
MYSQL和ORACLE区别:
事务提交不同:mysql默认自动提交,oralce默认不自动提交。需要手动提交,commit。
分页不同,limit和rownum。
事务的支持不同:mysql在innodb存储引擎的行级锁下支持事务,oracle完全支持。
mysql有自动增长的数据类型,插入记录时不用操作此字段。oalce没有自动增长类型,需要手动创建序列。
mysql可以用双引号包起字符串,oracle只能用单引号包起字符串。
日期字段:mysql有date和time日期字段,oracle只有date字段。
事务隔离级别不同: MySQL是可重复读隔离RR级别,而Oracle是读提交RC的隔离级别。
逻辑备份:mysql逻辑备份时需要锁定数据,才能保证备份的数据一致,oralce不用。
并发性:mysql以表锁为主,对资源锁定的粒度很大。innodb的引擎可以使用行级锁,但是这个行级锁机制依赖于索引,如果没有索引,或者SQL没有使用索引。那仍然使用表级锁。
语法:
oracle有decode,mysql if;
oracle可以使用表where连接;
oracle length(str),mysql char_length(str);
Oracle to_char(),mysql date_format();
Oracle to_date(),mysql str_to_date();
Oracle to_number(),mysql cast();