现在市面上mysql主流版本号是5.5, 5.7 ,8.0,5.7这个版本相对来说稳定性和兼容性都已经得到市场的验证,是比较好的一个版本。
###1.mysql中有MyISAM引擎与InnoDb引擎,他们之间区别是什么
InnoDb索引文件和数据文件是在一起的,只要查找索引文件后就可以连接到数据文件,查一次即可,效率高。现在主流使用InnoDb引擎
即使不创建主键id,mysql还是会默认创建一个rowid作为自增主键,用来做范围查询,这个rowid是看不到的,uuid是随机的,这个没法做范围查询。
###3.慢查询定位
慢查询 show variables like '%query%'; #查询慢日志相关信息,定位慢查询 slow_query_log 默认是off关闭的,使用时,需要改为on打开 slow_query_log_file 记录的是慢日志的记录文件 long_query_time 默认是10秒,每次执行的sql达到这个时长,就会被记录 show status like '%slow_queries%'; 查看慢查询状态 set global long_query_time = 1 修改慢查询时间1s set global slow_query_log = 'ON' #开启慢查询 注意:修改慢查询时间后,记得需要重新连接才可以生效,只要把navicat关掉重新打开就行,不需要重启mysql 可以通过EXPLAIN查询该语句是否生效,全部扫描 通过慢查询定位一些查询比较慢的sql语句,在使用explain 工具排查该sql语句索引是否有生效。 explain select * from person where id = 1 加上关键字explain就可以查询到该条sql的索引是否生效 SHOW KEYS FROM attence; id:选择标识符 select_type:表示查询的类型。 table:输出结果集的表 partitions:匹配的分区 type:表示表的连接类型 possible_keys:表示查询时,可能使用的索引 key:表示实际使用的索引 key_len:索引字段的长度 ref:列与索引的比较 rows:扫描出的行数(估算的行数) filtered:按表条件过滤的行百分比 Extra:执行情况的描述和说明询,又是上述三种复杂查询中 type列: 依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL 市场要求索引的级别起码在range,比如select * from person就是index,把所有的索引查询出来再查询数据,select * from person where id >1那这个就是range级别,是根据二叉树查询的有范围的。如果索引是index或者all就需要优化,性能太低。 误区: index级别扫描全部索引的文件,all: 全表物理扫描 select * from person where phone = '13918774587' and post_number = '0140' select phone,post_number from person where phone = '13918774587' and post_number = '0140' 如果查询速度慢,可以只返回索引字段,用索引查的返回的字段也是索引,如果返回的字段当中只要有一个不是索引里的,那就跟select * 没有任何区别 1.不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描 2. is null,is not null 也无法使用索引(解决方案,空值用专门特定常量值定义,比如def等) EXPLAIN SELECT * FROM employees WHERE name is null 3. mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫 EXPLAIN SELECT * FROM employees WHERE name != 'zhangsan' 4.字符串不加单引号索引失效 EXPLAIN SELECT * FROM employees WHERE name = 62440312321; EXPLAIN SELECT * FROM employees WHERE name = '62440312321'; 5.少用or,用它连接时很多情况下索引会失效 EXPLAIN SELECT * FROM employees WHERE name = 'zhangsan' or name = 'wangmazi'; 6.like以通配符开头('$abc...')mysql索引失效会变成全表扫描操作 EXPLAIN SELECT * FROM employees WHERE name like '%mei'; EXPLAIN SELECT * FROM employees WHERE name like 'mei%'; 问题:解决like'%字符串%'索引不被使用的方法? 1. 使用覆盖索引,查询字段必须是建立覆盖索引字段 EXPLAIN SELECT name FROM employees WHERE name like '%mei'; 使用like避免索引失效用like 'mei%'这种方式,原理就是索引全部都是符合左侧原则,如果%mei就相当于每个索引都查了下,mei%就相当于最左侧是mei然后rang范围查出来对应索引。 如果一定要用%%这种like可以用select name from employes where name like '%mei%' 这样的话都是查的索引文件并且返回索引,没有去data回表查,然后在通过select * from employes where name in ('上个sql查询到的所有name'),这个时候用的索引是ref性能会很高,使用子查询select * from employes where id in (select id from employes where name like '%mei%'); Mysql使用IN查询导致索引失效的情况 (https://blog.csdn.net/u010963948/article/details/90450014) explain select * from attence force index(department_id) where department_id in (2 , 20 ) 可以使用force index强制索引,原理就是mysql觉得那么多in,直接用all还快点,所以就取消了索引,但是实际测下来还是索引块,那就可以强制索引 可以设置单路排序的大小,超过这个大小就是双路,双路排序会回表,速度慢,但是不占内存.单路排序占用内存,但是数据都在内存里排序操作不会回表,性能高 SHOW VARIABLES LIKE '%max_length_for_sort_data%'; SET max_length_for_sort_data = 1024; left join左连接,左表为主,如果右表数据没有就全部为null right join右连接,右表为主,如果左表数据没有就全部为null inner join内敛: 扫描的时候会优先选择小表先进行扫描再去关联大表,保证性能。 left join和right join要保证性能要考虑优先在对应那侧放小表提升性能
Extra是null说明回表了,因为返回的字段当中有一些并没有建立索引
optimizer_trace 分析sql索引语句 第一步:开启optimizer_trace SET SESSION optimizer_trace="enabled=on",end_markers_in_json=on; 第二步:下面两句sql在navicat中一起执行,然后点击结果2就可以查看到了,一条条执行不行,必须要一起执行 SELECT * FROM person order by person_account_id; SELECT * FROM information_schema.OPTIMIZER_TRACE; 可以查看最下面的文档,搜索optimizer_trace就可以查询到 这个json关键字查询: join_preparation第一阶段:SQl准备阶段 join_optimization:第二阶段:SQL优化阶段 rows_estimation: 预估标的访问成本 range_analysis: 全表扫描情况 rows: 扫描行数 cost: 查询成本 (到底是全表扫描还是用索引就看这个cost谁更小花的时间越少就用哪种) potential_range_indexes: 查询可能使用的索引 analyzing_range_alternatives: 分析各个索引使用成本 chosen: 是否选择该索引 join_execution: 第三阶段:SQL执行阶段 可以查看: [https://blog.csdn.net/weixin_31476341/article/details/113909485](https://blog.csdn.net/weixin_31476341/article/details/113909485)
select count(*) from person; select count(1) from person; select count(id) from person; select count(name) from person; select count(*)和select count(1)性能是一样的没有任何区别。 select count(name)排除了name为null的数据 select count(id)包含其他字段为null的情况 理论上count(name)比count(id)要快,因为count(id)查找的叶子节点是id索引对应的data数据,需要从data数据里查,而name索引对应的是id,查完后不需要回表
show open tables; 查看表上加过的锁 unlock tables; 删除表锁 //删除主外键关联的表的强链接 SET foreign_key_checks = 0 删除外键约束 TRUNCATE TABLE attence 删表 SET foreign_key_checks = 1 启动外键约束 //如何杀死事务的进程号 select * from information_schema.innodb_trx t; 查询开启的事务信息 select t.trx_mysql_thread_id from information_schema.innodb_trx t; 查询开启的事务的进程号 kill 5; //开启事务提交和回滚 BEGIN; update person set avatar_url = null,body_url=NULL where phone = '13918789456'; COMMIT; ROLLBACK; mysql默认的事务隔离级别为 repeatable-read 可重复读 select @@tx_isolation; MySQL事务隔离级别 脏读: 当前session读取到另外session未提交的事务的数据,另外session有可能会回滚该数据。 可重复读: 当前事务中已经查询到数据,在事务结束之前,如果有其他的Session对该数据做修改并且提交,还是用原来的数据。 不可重复读: 当前事务中已经查询到数据,如果其他的Session对该数据发生改变的并且提交,用最新的数据。 幻读: 幻读是针对数据插入(INSERT)操作来说的。假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现好像刚刚的更改对于某些数据未起作用,但其实是事务B刚插入进来的,让用户感觉很魔幻,感觉出现了幻觉,这就叫幻读。(比如事务隔离级别是可重复读 select … for update 语句是通过查询进行加锁,也就是id=2这条数据begin后没有commit之前,查询好后,就将id=2这条数据进行了行锁,其他session无法对它进行修改 begin; select * from person where id=2 for update; commit; 间隙锁的作用 sessionA begin; update person set name='zhangsan6' where id>18 and id<22; commit; 从id>18 and id <22 上了间隙锁,在没有释放锁的时候 其他的session无法对该段位做操作。 sessionB INSERT INTO `person ` VALUES (19, 'zhangsan19', '500'); 如何避免行锁升级表锁(不管是delete或者update,where后面的条件一定要是索引字段,否则会查询全表,这样就会锁表) InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则都会从行锁升级为表锁。 sessionA begin; update person set name='zhangsan6' where balance='300'; commit; 修改的时候查询的条件不是索引字段,会走全表扫描 全表扫描的时候对每行数据都加上行锁 ,最终形成表锁。 sessionB 无法修改该任意一条数据,直接发生表锁。 删除表锁 unlock tables; 避免引起标所的方案,最好更新的时候使用索引字段,否则的话会进行全表扫描就会引发表锁 【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
shardingJDBC
ShardingJDBC官网 https://gitee.com/Sharding-Sphere https://shardingsphere.apache.org/document/current/cn/overview/ 使用说明 使用Sharding-JDBC 分库分表 https://www.cnblogs.com/coderzhw/p/11094305.html https://www.i847.cn/article/13.html