①、将范围查询的列放在复合索引的最后面。
②、列过滤的频繁越高,选择性越好,应该作为复合索引的前导列,适用于等值查找。
一般情况下,如果表有复合索引idx_status_create_time,我们都知道,单独用create_time去查询,MySQL优化器是不走索引,所以还需要再创建一个单列索引idx_create_time。其中Oracle是可以走索引跳跃扫描(Index Skip Scan),在MySQL 8.0也实现Oracle类似的索引跳跃扫描,在优化器选项也可以看到skip_scan=on。
--- 关闭索引跳跃扫描特性
optimizer_switch='skip_scan=off'
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UcKgr9e6-1662476964371)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/36a2c52d7ebf42c89b740ced0dccadb3~tplv-k3u1fbpfcp-zoom-1.image)]
含义 | 参数内容 | |
---|---|---|
id | select 的序列号 | id的顺序是按 select 出现的顺序增长的,id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行 |
select_type | 对应行是简单还是复杂的查询 | 1.simple: 简单查询。查询不包含子查询和union;2.primary:复杂查询中最外层的 select;3.subquery:包含在 select 中的子查询(不在 from 子句中)4.derived:包含在 from 子句中的子查询。MySQL会将结果存放在一个临时表中,也称为派生表 |
table | 表示正在访问哪个表 | |
partitions | ||
type | 关联类型或访问类型,即MySQL决定如何查找表中的行 | 依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL得保证查询达到range级别 |
possible_keys | 查询可能使用到的索引 | |
key | 显示采用哪个索引来优化对该表的访问 | |
key_len | 显示了mysql在索引里使用的字节数 | char(n):n字节长度,不可变,查询快但耗内存(可以存储名字,等定值的)varchar(n):2字节存储字符串长度,如果是utf-8,则长度 3n+2。查询慢但存储小tinyint:1字节smallint:2字节int: 4字节bigint:8字节date:3字节timestamp:4字节datetime:8字节NULL:1字节 |
ref | 显示了在key列记录的索引中,表查找值所用到的列或常量 | 常见的有:const(常量),字段名(例:film.id) |
rows | mysql估计要读取并检测的行数 | |
filtered | 是个一个百分比值 | |
extra | 展示的是额外信息 | Using index:使用覆盖索引;Using where:使用 where 语句来处理结果,查询的列未被索引覆盖;Using index condition:查询的列不完全被索引覆盖,where条件中是一个前导列的范围;Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。****Using filesort:将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一般也是要考虑使用索引来优化的。****Select tables optimized away:使用某些聚合函数(比如 max、min)来访问存在索引)的某个字段是****backward index scan关键字,译为中文就是倒叙索引范围查找 |
大部分即使添加了索引也不定会走,因此需要根据trace来分析,开启这个会影响sql的效率,是有使用的时候才开起它。
先执行sql语句,再查询表(INFORMATION_SCHEMA.OPTIMIZER_TRACE)查看他的分析结果。
-‐‐ 开启trace
set session optimizer_trace="enabled=on",end_markers_in_json=on;
--- 查看具体SQL
select tal_id from rental where 1=1
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE
--- 查看跟踪结果
SELECT trace FROM information_schema.OPTIMIZER_TRACE\G;
-‐‐ 关闭trace
set session optimizer_trace="enabled=off"
--- 强制索引
SELECT merchant_id, plan_id, bs_type,SUM(amount) sum_total
FROM bill_summary FORCE INDEX(tk_union_first)
--- trace结果集分析
https://blog.csdn.net/yanghao8866/article/details/107826931
分析结果中包含了为什么走不走索引的原因,分析了各种情况的成本。会结合数据量,效率等情况
分析文件:
\
①、order by limit 造成优化器选择索引错误
https://developer.aliyun.com/article/51065
系统变量:判断使用那种排序(max_length_for_sort_data)
OPTIMIZER_TRACE_MAX_MEM_SIZE=1024
分类:单路排序:查询的字段是没有查过指定的大小(默认是1024),会把查询的字段取出来放在内存或者磁盘上排序。
双路排序:查询的字段大于指定的指定的大小,把查询的主键取出来。其中都是放入到sort buffer中进行排序。去除主键还会回表进行查询。
Using filesort文件排序原理详解 filesort文件排序方式
单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer(1M)中进行排序;用trace工具可 以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key, packed_additional_fields >
双路排序(又叫回表排序模式):是首先根据相应的条件取出相应的排序字段和可以直接定位行 数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段;用trace工具 可以看到sort_mode信息里显示< sort_key, rowid >MySQL 通过比较系统变量 max_length_for_sort_data(默认1024字节) 的大小和需要查询的字段总大小来 判断使用哪种排序模式。
如果 字段的总长度小于max_length_for_sort_data ,那么使用单路排序模式; 如果字段的总长度大于max_length_for_sort_data ,那么使用 双路排序模式。
1、代码先行,索引后上
2、联合索引尽量覆盖条件
3、不要在小基数字段上建立索引
4、长字符串我们可以采用前缀索引
例如:index(name(20),age,position)。
5、where与order by冲突时优先where
6、基于慢sql查询做优化
关于慢sql查询不清楚的可以参考这篇文章:https://blog.csdn.net/qq_40884473/article/details/89455740
索引失效的部分场景 | |
---|---|
1 | mysql在使用不等于( != 或者 <> )的时候无法使用索引会导致全表扫描。 |
2 | 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描 |
3 | 使用Oracle内部函数导致索引失效.对于这样情况应当创建基于函数的索引。 |
4 | 首先建立函数索引,create index test_id_fbi_idx on test(round(id));然后 select * from test where round(id)=10; 这时函数索引起作用了 |
5 | 不要将空的变量值直接与比较运算符(符号)比较 |
6 | 不要在 SQL 代码中使用双引号 |
7 | 将索引所在表空间和数据所在表空间分别设于不同的磁盘chunk上,有助于提高索引查询的效率 |
8 | Oracle在进行一次查询时,一般对一个表只会使用一个索引 |
9 | like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。 |
10 | or语句前后没有同时使用索引。 |
11 | 在索引列上使用 IS NULL 或 IS NOT NULL操作 |
SQL优化建议索引不超过六个
注意:索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中):
sql使用注意点 | |
---|---|
1 | where使用<> 避免!= |
2 | 使用or的优化如SQL:SELECT id FROM A WHERE num =10 or num = 20 优化成:SELECT id FROM A WHERE num = 10 union all SELECT id FROM A WHERE num=20 |
3 | in的使用优化:在where后面,使用between and 或者使用 exits(select…)或者使用left join…on… |
4 | 使用like时,尽量不要再前面加%问题:解决like’%字符串%'索引不被使用的方法?a)使用覆盖索引,查询字段必须是建立覆盖索引字段EXPLAIN SELECT name,age,position FROM employees WHERE name like ‘%Lei%’;b)如果不能使用覆盖索引则可能需要借助搜索引擎 |
5 | 在where条件中,不要再=左边使用函数进行计算 |
6 | 任何地方都不要使用*,要用具体的字段,防止返回不必要的字段 |
7 | limit分页优化,偏移量较大时,效率会比较大 |
8 | 批量插入优化,尽量在一行中,值用一个list |
9 | 使用union all,避免使用unionunion尽量联合时会进行计算排除重复的,并进行排序,所以数据不存在重复结果集或者不在乎的时候,尽量使用union all |
10 | inner join和left、right inner性能较快,子查询的性能又比外连接性能慢 |
11 | exits代替in,not Exits替代not in |
12 | 用>=替代> |
13 | 少用or或in,用它查询时,非主键字段的索引会失效,主键索引有时生效,有时不生效,跟数据量有关,具体还得看mysql的查询优化结果 |
①、MySQL–Null的原理
疑问:判断null 使用is null 而不是使用 =null
原理:因为 null 是会在字段后面开辟空间,存放标记位所以判断的是标记位不是数值。
优化建议:所以尽量使用not null 并且设置默认值。除了test,long等
datetime—日期类型使用 1970-01-01 00:00:00;varchar使用’'(匹配字符串是从左到右,很高效);
优化前
select count(*) from table where ;
优化后
select 1 from table where … limit 1;
优化前 | 优化后 | 缺点 | |
---|---|---|---|
1、根据自增且连续的主键排序的分页查询 | select * from table limit 10000,10; | select * from table where id > 90000 limit 5; | 如果不是连续删除数据会有偏差 |
2.根据非主键字段排序的分页查询(使用覆盖索引优化) | select * from employees ORDER BY name limit 90000,5; | select * from employees e inner join (select id from employees order by name limit 90000,5) ed on e.id = ed.id; |
mysql的表关联常见有两种算法(小表驱动大表)
Nested-Loop Join 算法:一次一行循环地从第一张表(称为驱动表)中读取行,在这行数据中取到关联字段,根据关联字段在另一张表(被驱动表)里取出满足条件的行,然后取出两张表的结果合集。
Block Nested-Loop Join 算法:把驱动表的数据读入到 join_buffer 中,然后扫描被驱动表,把被驱动表每一行取出来跟 join_buffer 中的数据做对比。(没有采用索引,采用第一种方法,可能会导致查询一条就全表扫描不划算。)
1、 in()适合B表比A表数据小的情况。
2.、exists()适合B表比A表数据大的情况。
其中:count(1) 约= count(*) > count(name) > count(id)
如果name加了索引的话比id的快,否则id快
count(id),会扫描主键索引数,那非主键的索引数的数据量小反而更快,现在count(id)自动优化使用非主键索引常见优化方法
1、MyISAM存储引擎:其中不带where条件的count查询性能是很高的。MyISAM存储引擎的表的总行数会被mysql存储在磁盘上。
2、需要知道表总行数:
show table status
show table stauts like"table"
3、将总数维护到Redis里:插入或删除表数据行的时候同时维护redis里的表总行数key的计数值(用incr或decr命令),但是这种方式可能不准,很难保证表操作和redis操作的事务一致性
4、增加计数表:插入或删除表数据行的时候同时维护计数表,让他们在同一个事务里操作
1、MySQL支持两种方式的排序filesort和index,Using index是指MySQL扫描索引本身完成排序。index效率高,filesort效率低。
2、order by满足两种情况会使用Using index。
order by语句使用索引最左前列。
使用where子句与order by子句条件列组合满足索引最左前列。
3、尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最左前缀法则。
4、如果order by的条件不在索引列上,就会产生Using filesort。
5、能用覆盖索引尽量用覆盖索引
6、group by与order by很类似,其实质是先排序后分组,遵照索引创建顺序的最左前缀法则。对于group by的优化如果不需要排序的可以加上order by null禁止排序。注意,where高于having,能写在where中 的限定条件就不要去having限定了。
7、GROUP BY 条件字段必须在同一个索引中最前面的连续位置;在使用GROUP BY 的同时,只能使用 MAX 和 MIN 这两个聚合函数
补o,如果是11 011
id` TINYINT(2) UNSIGNED ZEROFILL
connect timeout:建立数据库连接超时
建立连接超时
socket timeout:socket读取超时
慢sql
statement timeout:单个sql执行超时
transaction timeout:事务执行超时,一个事务中可能包含多个sql
事务超时
get connection timeout:从连接池中获取链接超时
获取连接超时
--- 表
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='应用表';
--- 字段
ALTER TABLE `t_order`
MODIFY COLUMN `remark` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '订单备注'
--- 查看数据库编码show variables like '%char%'
show variables like '%char%'
--- 设置编码格式
set character_set_server=utf8mb4
character_set_client (客户端来源数据使用的字符集)
character_set_connection (连接层字符集)
character_set_database (当前选中数据库的默认字符集)
character_set_results (查询结果字符集)
character_set_server (默认的内部操作字符集)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HVG1aBpa-1662476964372)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/99acdee25bcb4c3ea68fadcc172ce1d6~tplv-k3u1fbpfcp-zoom-1.image)]
功能 | 详情 | ||
---|---|---|---|
profile | 查看profile是否开启 | show variables like ‘profiling%’; | – ALL;显示所有的开销信息-- BLOCK IO:显示块IO相关开销-- CONTEXT SWITCHES:上下文切换相关开销-- CPU:显示CPU相关开销-- IPC:显示发送和接受相关开销-- MEMORY:显示内存相关开销-- PAGE FAULTS:显示页面错误相关开销-- SOURCE:显示和Source_function, Source_file,Source_line相关的相关开销-- SWAPS:显示交换次数相关开销 |
开启profile功能 | set profiling=1; | ||
查看profile | show profiles; | ||
查看profile中cpu和磁盘IO的明细 | show profile cpu,block io for query 391; | ||
查看所有明细 | show profile ALL for query 422; | ||
trance分析 | 查看trance是否开启 | show variables like ‘optimizer_trace’; | |
会话级别临时开启 | set session optimizer_trace=“enabled=on”,end_markers_in_json=on; | ||
设置内存大小 | SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000; | ||
永久开启 optimizer_trace(重启失效) | set optimizer_trace=“enabled=on”; | ||
执行sql完后,执行进行分析 | SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE | ||
锁分析 | 查看行锁记录 | show status like’innodb_row_lock%'; | 有3种配置模式:0、1、2,分别对应”传统模式”, “连续模式”, “交错模式”。-- 传统模式:涉及auto-increment列的插入语句加的表级AUTO-INC锁,只有插入执行结束后才会释放锁。这是一种兼容MySQL 5.1之前版本的策略。-- 连续模式:可以事先确定插入行数的语句(包括单行和多行插入),分配连续的确定的auto-increment值;对于插入行数不确定的插入语句,仍加表锁。这种模式下,事务回滚,auto-increment值不会回滚,换句话说,自增列内容会不连续。-- 交错模式:同一时刻多条SQL语句产生交错的auto-increment值。 |
查看自增锁模式 | show variables LIKE ‘innodb_autoinc_lock_mode’; | ||
事务 | 查看事务 | show engine innodb status; |
MYSQL 经纬度字段类型
INSERT INTO my_user
( point,id ) VALUES ( ST_GeomFromText(‘POINT(1 1)’),1);
SELECT id ,ST_X(point) x ,ST_Y(point) y ,point FROM my_user
;
UPDATE my_user
SET point = ST_GeomFromText(‘POINT(1337 125)’) where id =1;