1、为啥要设置主键
如果不设置主键,MySQL 也会自己设定隐藏主键,为了提高业务查询效率,提倡设置主键
2、为啥非要设定自增主键
如果使用自定义主键,会导致MySQL插入数据步骤增多(例如为寻找合适的插入位置要移动数据),增加索引碎片,原因是对应随机自定义主键的索引页有可能已落到磁盘上,频繁读取和回写,增加系统开销,频繁移动和分页,造成索引碎片。后续可通过 optimize table 手动处理。
3、mysql如何实现分库分表
当数据量大的时候,导致查询变慢,需要分表。
分表分纵向和横向。
纵向:字段较多,拆分扩展表。
横向:库内分表,简单表拆分;分库分表,可按业务,也可按ID散列。
4、为啥不建议主键带业务含义
因为业务会变,主键不能随便变,会导致索引页分裂,产生索引碎片
5、为啥不直接存储图片、音频、视频
因为他们太大,占用内存高,binlog 大,更新和维护麻烦,内存临时表不支持TEXT,BLOB,查询效率极低。
6、为什么字段尽量设置 NOT NULL
索引开销变大;可能导致查询结果异常;不利于SQL书写。

关于优化
1、where 执行顺序
从左到右执行,所以第一个条件应该排除最多的数据
2、应该在这些列创建索引
经常搜索;经常连接;经常按范围搜索;经常排序;
3、联合索引
规则:从左到右使用索引字段,一个查询可以只使用部分索引,只针对最左侧第一个字段有效,例如 key(a,b,c),有效的查询是:a, ab, abc,b,bc,c不起效。类似电话本,知道姓比知道名好。遵循最左前缀原则。
4、联合索引原则
字段值去重后最多的放前面
5、啥情况不应该建索引
数据少;频繁写的表;字段值重复且分类数量区别不大(type、status);
6、mysql CPU 100%怎么办
show processlist;
show variables like ‘log_slow_queries’;
show variables like ‘long_query_time’;
查看 slow log;
explain 慢查询语句;(type+extra很重要,type好-差顺序:const、eq_reg、ref、range、indexhe和ALL;extra出现 using temporary 和 using filesort 说明有问题)
7、表锁和行锁的区别
悲观锁:操作之前先上锁;
行锁:粒度小,冲突低,并发好;开销大,加锁慢,死锁。行锁发生时机:针对索引字段进行查询。
表锁:粒度大,冲突搞,并发坏;开销小,加锁块,不死锁。
8、主键和索引
主键只有一个,索引可以多个
主键不可为空,所以可以
9、优化方法
最优属性;最优长度;字段NOT NULL;
JOIN代替子查询;
建立索引;
优化 SQL 语句;
10、汉字占用长度
UTF-8: 3 字节;
GBK:2 字节;
11、共享锁
一个事务读取数据,会阻塞其他事务写操作
12、排他锁
一个事务写一条记录操作,会阻塞其他事务对同一表的读写操作
13、间隙所
对一个范围内的数据加锁,是间隙锁
14、临键锁
特殊的间隙锁
15、MVCC
乐观锁的一种实现方式,采用隐藏版本号实现多版本并发读写
隐藏版本号字段:trx_id(最近事务ID)、roll_pointer(上一个版本信息)
16、索引原理
关键词:二叉树、平衡树、红黑树、B树、B+树
17、主从同步
原理:Slave根据配置从Master得到 binlog 日志,然后重写数据
方式:异步复制、半同步复制、GTID复制

MySQL 查看数据库状态
show status like ‘%xxx%’;
Aborted_clients 由于客户没有正确关闭连接已经死掉,已经放弃的连接数量。
Aborted_connects 尝试已经失败的MySQL服务器的连接的次数。
Connections 试图连接MySQL服务器的次数。
Created_tmp_tables 当执行语句时,已经被创造了的隐含临时表的数量。
Delayed_insert_threads 正在使用的延迟插入处理器线程的数量。
Delayed_writes 用INSERT DELAYED写入的行数。
Delayed_errors 用INSERT DELAYED写入的发生某些错误(可能重复键值)的行数。
Flush_commands 执行FLUSH命令的次数。
Handler_delete 请求从一张表中删除行的次数。
Handler_read_first 请求读入表中第一行的次数。
Handler_read_key 请求数字基于键读行。
Handler_read_next 请求读入基于一个键的一行的次数。
Handler_read_rnd 请求读入基于一个固定位置的一行的次数。
Handler_update 请求更新表中一行的次数。
Handler_write 请求向表中插入一行的次数。
Key_blocks_used 用于关键字缓存的块的数量。
Key_read_requests 请求从缓存读入一个键值的次数。
Key_reads 从磁盘物理读入一个键值的次数。
Key_write_requests 请求将一个关键字块写入缓存次数。
Key_writes 将一个键值块物理写入磁盘的次数。
Max_used_connections 同时使用的连接的最大数目。
Not_flushed_key_blocks 在键缓存中已经改变但是还没被清空到磁盘上的键块。
Not_flushed_delayed_rows 在INSERT DELAY队列中等待写入的行的数量。
Open_tables 打开表的数量。
Open_files 打开文件的数量。
Open_streams 打开流的数量(主要用于日志记载)
Opened_tables 已经打开的表的数量。
Questions 发往服务器的查询的数量。
Slow_queries 要花超过long_query_time时间的查询数量。
Threads_connected 当前打开的连接的数量。
Threads_running 不在睡眠的线程数量。
Uptime 服务器工作了多少秒。

– 查询非 Sleep 状态的链接,按消耗时间倒序展示,自己加条件过滤
select id, db, user, host, command, time, state, info
from information_schema.processlist
where command != ‘Sleep’
order by time desc

这样就过滤出来哪些是正在干活的,然后按照消耗时间倒叙展示,排在最前面的,极大可能就是有问题的链接了,然后查看 info 一列,就能看到具体执行的什么 SQL 语句了,针对分析
展示列解释:

  • id - 线程ID,可以用:kill id; 杀死一个线程,很有用
  • db - 数据库
  • user - 用户
  • host - 连库的主机IP
  • command - 当前执行的命令,比如最常见的:Sleep,Query,Connect 等
  • time - 消耗时间,单位秒,很有用
  • state - 执行状态,比如:Sending data,Sorting for group,Creating tmp table,Locked等等,很有用,其他状态可以看看本文最后的参考文章
  • info - 执行的SQL语句,很有用

上面提到的 线程ID 是可以通过 kill 杀死的;所以上面基本上可以把有问题的执行语句找出来,然后就可以 kill 掉了,那么一个一个来 kill 么?
– 查询执行时间超过2分钟的线程,然后拼接成 kill 语句
select concat(‘kill ‘, id, ‘;’)
from information_schema.processlist
where command != ‘Sleep’
and time > 2*60
order by time desc

查看binlog日志(基于row模式)
mysqlbinlog –no-defaults -v -v –base64-output=DECODE-ROWS mysql-bin.000001 | tail -n 200

作者:Wolf  创建时间:2023-10-26 10:14
最后编辑:Wolf  更新时间:2023-11-27 23:47