数据库规范与SQL调优

news2024/10/7 10:21:19
数据库设计规范章节,依旧以《阿里巴巴Java开发手册》为原型进行修正和完善。
MySQL规约
(一) 建表规约
(二) 索引规约
(三) SQL规约
(四) ORM规约
(一) 建表规约
1. 【强制】 表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是
unsignedtinyint(
1表示是,0表示否),此规则同样适用于odps建表。
说明:任何字段如果为非负数,必须是unsigned。
2. 【强制】 表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划
线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名
称需要慎重考虑。
正例: getter_admin task_config level3_name
反例: GetterAdmin taskConfig level_3_name
3. 【强制】 表名不使用复数名词。
说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于DO类名
也是单数形式,符合表达习惯。
4. 【强制】 禁用保留字,如desc、range、match、delayed等,请参考MySQL官方保留
字。
5. 【强制】 唯一索引名为uk 字段名;普通索引名则为idx 字段名。
说明:uk 即 unique key;idx 即index的简称。
6. 【强制】 小数类型为decimal,禁止使用float和double。
说明:float和double在存储的时候,存在精度损失的问题,很可能在值的比较时,得
到不正确的结果。如果存储的数据范围超过decimal的范围,建议将数据拆成整数和
小数分开存储。
7. 【强制】 如果存储的字符串长度几乎相等,使用char定长字符串类型。
8. 【强制】 varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果
存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响
其它字段索引效率。
9. 【强制】 表必备字段:id, creation_time,creator,modified_time,modifier,valid。
说明:其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。
gmt_create,gmt_modified的类型均为date_time类型。
10. 【强制⭐】 所有表必须有主键,主键必须保证有序。Mysql的锁,锁的是主键索引树,没主
键会导致所有操作都是锁全表。而主键无序,会导致频繁页分裂,大大降低更新速度。
11. 【推荐】 表的命名最好是加上“业务名称_表的作用”。
正例: tiger_task / tiger_reader / mpp_config
12. 【推荐】 库名与应用名称尽量一致。
13. 【推荐】 如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
14. 【推荐】 字段允许适当冗余,以提高性能,但是必须考虑数据同步的情况。冗余字段
应遵循:
不是频繁修改的字段。
不是varchar超长字段,更不能是text字段。
正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存储
类目名称,避免关联查询。
15. 【推荐】一般情况下, 单表行数超过500万行或者单表容量超过2GB,才推荐进行分
库分表。
如果某张表字段特别多,或者字段比较大,则需要提前进行。按照以前的经验,
110个字段的表,在数据量超过100万时,已经会比较严重地拖慢整体性能了。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分
表。
16.【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是
提升检索速度。
1 正例:人的年龄用 unsigned tinyint (表示范围 0-255 ,人的寿命不会超过 255 岁);海龟就
必须是 smallint ,但如果是太阳的年龄,就必须是 int ;如果是所有恒星的年龄都加起来,那么
就必须使用 bigint (二) 索引规约
1. 【强制】 业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。
说明:不要以为唯一索引影响了insert速度,这个速度损耗可以忽略,但提高查找速
度是明显的;另外,即使在应用层做了非常完善的校验和控制,只要没有唯一索引,
根据墨菲定律,必然有脏数据产生。
2. 【强制】 超过三个表禁止join。需要join的字段,数据类型保持绝对一致;多表关联查
询时,保证被关联的字段需要有索引。
说明:即使双表join也要注意表索引、SQL性能。
3. 【强制】 在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索
引,根据实际文本区分度(离散度)决定索引长度。
说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索
引,区分度会高达90%以上,可以使用count(distinct left(列名,索引长度))/count(*)
的区分度来确定。
4. 【强制】 页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
说明:索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法
使用此索引。
5. 【强制】 对于联合索引左边第一个能够覆盖到的索引列,不要再单独添加索引。
6.【强制】创建索引的列,不要有Null值,查询Null值无法走索引。
7. 【推荐】 如果有order by的场景,请注意利用索引的有序性。order by最后的字段是
组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查
询性能。
1 正例: where a=? and b=? order by c; 索引: a_b_c
2 反例:索引中有范围查找,那么索引有序性无法利用,如: WHERE a>10 ORDER BY b; 索引 a_
b 无法排序。
8. 【推荐】 利用覆盖索引来进行查询操作,来避免回表操作。
说明:如果一本书需要知道第11章是什么标题,会翻开第11章对应的那一页吗?目
录浏览一下就好,这个目录就是起到覆盖索引的作用。
1 正例:能够建立索引的种类:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的一种效
果,用 explain 的结果, extra 列会出现: using index
9. 【推荐】 利用延迟关联或者子查询优化超多分页场景。 说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,
返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,
要么对超过特定阈值的页数进行SQL改写。
10. 【推荐】 SQL性能优化的目标:至少要达到 range级别,要求是ref级别,如果可以
是consts最好。
说明:
1)consts单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取
到数据。
2)ref指的是使用普通的索引(
normal index)。
3)range对索引进行范围检索。
11. 【推荐】 建组合索引的时候,区分度最高的在最左边(最左匹配原则)。
12.【参考】创建索引时避免有如下极端误解:
误认为一个查询就需要建一个索引。
误认为索引会消耗空间、严重拖慢更新和新增速度。
误认为唯一索引一律需要在应用层通过“先查后插”方式解决。
误认为索引建了就一定会走索引。
误认为索引一定能提高查询效率。
(三) SQL规约
1. 【强制】 不要使用count(列名)或count(常量)来替代count(
*) ,count(
*) 就是
SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。
说明:count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的
行。
2. 【强制】 count(distinct column)计算该列除NULL之外的不重复数量。注意
count(distinct column1, column2)如果其中一列全为NULL,那么即使另一列有不同的
值,也返回为0。
1 正例:先快速定位需要获取的 id 段,然后再关联:
SELECT a.* FROM 1 a, (select id from 1 where 条件 LIMIT 100000,20 ) b wh
ere a.id=b.id
2
反例: explain 表的结果, type=index ,索引物理文件全扫描,速度非常慢,这个 index 级别
比较 range 还低,与全表扫描是小巫见大巫。
1
1 正例:如果 where a=? and b=? a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可。
说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如: wherea
>?and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列。
2 3. 【强制】 当某一列的值全是NULL时,count(column)的返回结果为0,但
sum(column)的返回结果为NULL,因此使用sum(column)时需注意NPE问题。
1 正例:可以使用如下方式来避免 sum NPE 问题: SELECT IF(ISNULL(SUM(g)),0,SUM(g))
FROM table;
4. 【强制】 使用ISNULL()来判断是否为NULL值。注意:NULL与任何值的直接比较都为
NULL。
说明:
1) NULL<>NULL的返回结果是NULL,而不是false。
2) NULL=NULL的返回结果是NULL,而不是true。
3) NULL<>1的返回结果是NULL,而不是true。
5. 【强制】 在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页
语句。
6.【强制⭐】不得使用外键与级联,一切外键概念必须在应用层解决。
说明:(概念解释)学生表中的student_id是主键,那么成绩表中的student_id则为
外键。如果更新学生表中的student_id,同时触发成绩表中的student_id更新,则为
级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更
新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
7. 【强制】 禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
8. 【强制】 数据订正时,删除和修改记录时,要先select,避免出现误删除,确认无误
才能执行更新语句。
9. 【强制】 删除数据时,禁止“delete from Table where Condition”。必须先查询出待删除的
数据,然后根据数据ID删除。程序如果没有传入Condition的条件,最终结果不是不删除数据,
而是删除所有数据,必须避免。
10. 【推荐】 in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数
量,控制在1000个之内。
11.【参考】如果有全球化需要,所有的字符存储与表示,均以utf-8编码,那么字符计
数方法
注意:
说明:
SELECT LENGTH("轻松工作");返回为12
SELECT CHARACTER_LENGTH("轻松工作");返回为4
如果要使用表情,那么使用utfmb4来进行存储,注意它与utf-8编码的区别。 12.【参考】TRUNCATETABLE比 DELETE速度快,且使用的系统和事务日志资源少,
但TRUNCATE无事务且不触发trigger,有可能造成事故,故不建议在开发代码中使用此
语句。
说明:TRUNCATE TABLE在功能上与不带 WHERE子句的 DELETE语句相同。
(四) ORM规约
1. 【强制】 在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确
写明。
说明:
1)增加查询分析器解析成本。
2)增减字段容易与resultMap配置不一致。
2. 【强制】 POJO类的boolean属性不能加is,而数据库字段必须加is_,要求在
resultMap中进行字段与属性之间的映射。
说明:参见定义POJO类以及数据库字段定义规定,在sql.xml增加映射,是必须的。
3. 【强制】 不要用resultClass当返回参数,即使所有类属性名与数据库字段一一对应,
也需要定义;反过来,每一个表也必然有一个与之对应。
说明:配置映射关系,使字段与DO类解耦,方便维护。
4. 【强制】 xml配置中参数注意使用:#{},#param#不要使用${}此种方式容易出现SQL
注入。
5. 【强制】 iBATIS自带的queryForList(String statementName,int start,int size)不推荐
使用(它是基于内存的分页方式,存在深分页问题)。
说明:其实现方式是在数据库取到statementName对应的SQL语句的所有记录,再
通过subList取start,size的子集合,线上因为这个原因曾经出现过OOM。
1 正例:在 sqlmap.xml 中引入 #start#, #size#
2 Map<String, Object> map = new HashMap<String, Object>();
3 map.put("start", start);
4 map.put("size", size);
6. 【强制】 不允许直接拿HashMap与Hashtable作为查询结果集的输出。
7. 【强制】 更新数据表记录时,必须同时更新记录对应的更新人与更新时间。对于拿不
到更新人的场景,可以统一使用保留字”system“,不要留空。
8. 【推荐】 不要写一个大而全的数据更新接口,传入为POJO类,不管是不是自己的目
标更新字段,都进行update table set c1=value1,c2=value2,c3=value3;这是不对的。 执行SQL时,尽量不要更新无改动的字段,一是易出错;二是效率低;三是binlog增加
存储。
9.【推荐】编写查询语句”select column1,column2,... from table where XXX“时,字
段的个数如果比较少,可以适当冗余。
试想一个场景:代码中同时存在针对某个实体的查询方法,它们的入参和返回值完
全一样,只有条件不同,这很容易被误解两个方法的返回值包含的属性值也一致。但如
果底层的实现中,select 的列名不一样,则很容易导致空指针。
思考:只查询需要的字段,数据库只需要返回用得到的字段即可,但方法可能有歧
义导致误用。查询全量字段,会要求数据库返回更多的信息,不过方法含义明确,不会
因为漏了字段值而导致问题。
10.【参考】@Transactional事务不要滥用。事务会影响数据库的QPS,另外使用事务
的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修
正等。
11.【参考】中的compareValue是与属性值对比的常量,一般是数字,表示相等时带上
此条件;表示不为空且不为null时执行;表示不为null值时执行。
12.【参考】作为更新场景的补充,为了不全量更新,一般会先判断传入的值是否为空,不为空
则更新。此时如果确实想设置某些字段的值为空,则无法实现。这种情况下,建议单独写一个设
置空值的方法,而不是通过一个全量更新的方法实现。
数据库层的调优
这里主要是一些与数据库调优相关的内容,包括数据库服务器,SQL分析等。
数据库服务器的性能
服务器端的分析集中在这几个方向上:硬件资源。数据库架构,以及数据库实例参数优化。
硬件资源分析
1,使用top命令查看CPU负载。
2,使用free命令查看内存使用情况。
3,使用iostat工具查看磁盘I/O使用情况。
4,使用vmstat命令查看系统的负载情况。
5,使用perf top命令查看系统热点情况。
6,使用nmon工具监控系统一段时间的整体情况。
使用腾讯云数据库时,也可以用腾讯云提供的相关工具。 如果发现数据库主机的CPU、
I/O、内存等使用率很高,那么原因有两种:
1,数据库实例存在性能瓶颈。
2,实例所在的机器硬件本身存在问题(可能性比较小,也容易排除) 。
数据库架构分析
目前公司主要是云数据库架构,依托腾讯云本身的能力,这一块的架构分析可以略过或找腾
讯云的售后进行支持。 服务器调优
数据库服务器调优。可以结合业务场景对数据库参数进行优化。以下是一个优化示例。
例如:有一个密集交易型数据库服务器配置如下:
CPU:4路8核。
内存:256G。
磁盘阵列:1T。
那么,推荐的参数设置如下:
识别慢SQL
目前使用腾讯云数据库,它们提供了数据库监控以及慢日志监控等功能,可以直接拿到慢
SQL。接下来按并发度对这些SQL进行分类:
1,并发非常高。SQL特征:SQL的条数很少(按5%统计),但是执行频率非常高,甚至达到
每秒上百次,只要一慢,系统很可能瘫痪。
优化级别:最优先处理。
优化方向:
对SQL本身进行优化,调到最优。
对发起SQL请求的应用进行优化,减少执行次数。包括使用缓存,多次请求合并为一次
等等。
2,并发一般 。SQL特征:占大多数(按80%统计),如果有慢的,对系统整体稳定性影响不
大,但是会造成局部的某些操作慢。
优化级别:次优先处理。
优化方向:对SQL本身进行优化,综合考虑索引,SQL改写等方式。
3,并发很少特别慢。SQL特征:数量少(按15%统计),往往是很复杂的查询,可能一天就
执行几次,对系统整体影响不大,但是优化难度很大。
优化级别:最后处理 。
优化方向:对SQL本身进行优化,同时可以对这类SQL有一定容忍度。
阻塞与死锁分析
死锁与阻塞是最为常见的两个性能杀手。可以用一些SQL来观测SQL的执行情况:
【show processlist】:此命令可以查看服务端线程状态。利用这些信息,可以找到耗时比
较长的环节并对其进行优化。还可以对阻塞的线程进行kill。使用【show processlist】会列出一
系列信息,其含义如下:
1,id。这是线程的唯一标记,【
kill {id}】可以终止该线程。
2,user。这个字段表示启动该线程的用户。
3,host。这个字段表示发起该连接的host。
4,db。这个字段表示操作的数据库是哪个。
5,command。表示操作的命令,包括SQL语句也是一种命令。
6,time。表示该操作持续了多久。
7,state。表示该线程当前处于什么状态。
8,info。包含前100个字符的Sql语句。如果想查看完整SQL,可以使用【show full processlist】。
【show status】:此命令可以查看Mysql服务器的运行状态,重启后状态信息会被清空。
还可以带上作用域,比如【
show global status】表示查看全局状态。
【show engine】:此命令用于查看存储引擎的状态。包括事务持有的表锁、行锁信息;事
务的锁等待情况;线程信号量等待;文件IO 请求;buffer pool 统计信息等。
死锁的特征:
1,死锁是相互堵塞。
2,数据库自动识别死锁并解锁。
3,SQL日志中会记录死锁信息。 避免数据库死锁需要采取以下措施:
1,减少事务的数量:减少并发事务的数目是避免死锁的首要步骤。
2,统一事务处理:尽量将对同一数据库表的更新操作放在同一个事务中,以减少出现死锁
的机会。
3,按照相同的顺序访问资源: 所有事务都按照相同的顺序来访问资源,以避免出现交叉等
待的情况。
4,使用低级别锁:尽可能使用低级别锁,例如行锁而不是表锁,以减少出现死锁的机会。
5,缩短锁定时间:尽量缩短锁定时间,并在完成后立即释放锁,以便其他事务可以及时访
问相关资源。
6,定期清理无用的锁:通过定期清理不再使用的锁,可以避免死锁的产生。
7,使用数据库提供的工具检测死锁:大部分数据库系统都提供了用于检测死锁的工具或
API,可以使用这些工具或API来监视数据库的死锁情况,并及时采取措施。
8,优化数据库设计和查询:优化数据库表格设计和查询语句,包括索引的建立、SQL 查询
语句的优化等,可以降低数据库死锁的风险。
阻塞的特征:
1,阻塞的SQL不会互相影响,它是单向的。
2,数据库无法自动识别阻塞并进行处理。
3,SQL日志中不会记录阻塞信息,表现形式只会是某SQL执行时间超长。
处理阻塞需要人工介入,大致方向有两个:减少并发操作,以及减少慢SQL。具体措施:
1,使用低级别锁:尽量使用低级别的行级别锁而不是高级别的表级别锁,以减少对资源的
阻塞。
2,使用索引: 通过在 WHERE 子句中使用索引列可以极大地加快 SQL 查询速度,从而减
少对相关资源的占用时间。
3,分批处理数据:如果需要处理大量数据,可以将其分批处理,以便避免一次性占用过多
的资源。
4,避免长事务和长查询:长时间运行的事务和长时间运行的查询会持续占用资源,导致其
他操作被阻塞。应该避免这种情况并定期清理无用的事务和查询。
5,调整数据库参数: 可以通过调整数据库参数来优化 SQL 执行性能,例如增加缓存大
小、调整线程池大小等。
6,定期优化数据库: 定期检查和优化数据库表格结构、索引、存储引擎等,可以提高数据
库的性能和响应速度。
7,合理设计 SQL 查询语句:合理的 SQL 查询语句设计可以有效地降低系统的负载和阻塞
风险。
SQL执行流程分析
对SQL执行流程所涉及的每一个环节进行优化,最终结果就是最优的。按照这个思路,先来
看看SQL执行流程: 客户端层的优化:
1,减少连接消耗:多次请求合并为一次,合理设置连接池的大小和连接施放时间。注意连
接数并不是越多越好。连接过多除了导致资源消耗增加外,还会额外引入更多的线程切换成本。
这里提供一个经验公式用于推断连接数的个数:【连接数=CPU核心数*2+1】
2,降低查询频率:合理使用缓存,将多条请求合并为同一条。
Mysql连接层的优化:
1,增加连接数。
2,及时释放不使用的连接。
3,Mysql相关参数调优。
查询缓存层的优化:查询缓存层设计得比较纠结,默认已经禁用了,仅当读远远大于写的场
景才有用。这一层的优化可以忽略。
SQL解析器和预处理器:这两个组件的作用是生成一颗正确的语法树。它的使用对用户来说
是黑盒,无法干预。
查询优化器:这一层会根据语法树生成多个执行计划,并进行优选。对SQL的优化,主要集
中在这里。
执行引擎:这一层根据执行计划进行调度,对用户来说,只能通过干预执行计划来间接干预
执行引擎的工作。
存储引擎层的优化:根据业务场景选择合适的存储引擎。例如归档表往往对事务的要求比较
弱,又以读为主,可以设置使用Mysiam引擎。再比如一些高频使用的小表可直接使用Memory
引擎常驻内存。
分析执行计划
在SQL语句前面加上explain并执行,可以列出该sql语句的执行计划,其语法格式如下:
explain {sql}】。在MySQL 5.6.3 以前的版本,只能分析SELECT。MySQL5.6.3以后就可以
分析update、delete和insert了。
一个典型的执行计划信息如下: 可以看到上述SQL语句出现了多行执行计划信息。这些执行计划表达的含义就是该SQL执行
时需要经过的步骤和其它信息,每条数据就是执行计划的一个步骤。接下来详细看看每个字段的
含义。
id字段:
id表示SQL语句执行的顺序。数字越大的执行计划越先被执行。如果数字相同,则按从上往
下的顺序依次执行。例如,子查询的优先级会高于外层查询。
如果是并列的查询,没有父子之分,查询优化器会自动进行优化:它会选用笛卡尔积相对较
小的结果作为中间结果,从而使得它们先被执行。Mysql的优化器是基于开销的,更小的中间结
果消耗更少的资源。此外,这也要求我们在做优化时,选择更小的表作为驱动表。
select_type字段:
这个字段表示查询的类型。查询类型很多,这里列举几个常见的:
1,simple。simple表示普通查询,它不包含子查询也不包含union查询。
2,primary。如果一个SQL语句包含子查询,那么最外层的查询类型就是primary。
3,subquery。如果一个SQL语句包含子查询,那么最内层的子查询类型就是subquery。
4,derived。意思是衍生查询。如果在得到最终结果之前,一个查询操作用到了临时表,那
么该查询的类型就是derived。比如一个union查询,Mysql会先执行union右边的语句,得到中
间结果放到临时表里,然后执行union左边的语句并与刚刚的临时表关联,其类型就是derived。
5,union。使用了union查询时,出现在union右边的查询会被标记为union类型。
6,union result。这种类型表示所有的union语句执行完毕后产生的中间结果。即使有多个
union查询,union result也只有一项。
table字段:
table字段表示查询过程中用到的表,包括普通的表和中间结果的表。普通表就不用细说
了,显示哪个表名,就表示针对那张表的查询。在union查询时,有时候table字段会显示类似
<union1,3,4>】这种值。这个值表示把ID为1,3,4的查询产生的结果集,作为当前查询所使
用的table。
type字段:
这个字段很关键,其含义是连接类型。不同的连接类型其执行效率差别很大,下面按性能由
高到低的顺序排列它们,并分别解释每一项的含义:
1,system。system表示查询系统表,表里只有一行记录。这个是最快的,然而是一种特
例,没有讨论的价值,基本不会出现。
2,const。它表示通过索引一次就找到了。通过一次索引就能找到数据的情况只有一种:
通过唯一索引查询数据,并且只查询到了一条数据。例如【
select * from t_table where
id=1】。
3,eq_ref。它通常出现在join语句中。对于前表中的每个索引列,都只能匹配到后表中的
唯一结果,此时后表的连接类型就是eq_ref。既然只能匹配到唯一结果,那多半是唯一性的索引
了。一般而言,join语句后面on的条件是唯一索引时会匹配到这种类型。
4,ref。它也是通常出现在join语句中。如果使用的不是唯一性的索引,那么前表中的索引
列的值可能对应后表中的多个结果,此时后表的连接类型就是ref。一般而言,join语句后面on 的条件是非唯一索引时会匹配到这种类型。
5,range。range表示使用索引进行范围查找。通常【
in (...),between... and ...】或者
【where column_a>{number}】这种类型的语句会匹配到range类型。
6,index。index的意思是走索引的全表扫描。将所有索引扫一遍去找对应结果,这个已经
很慢了。遇到index类型的查询,说明需要优化。
误解:很多人认为“index”表示走索引的查询,这个理解大大的错,index的性能很低,说不
定还不如顺序的全表扫描,至少不用随机读。
7,all。all是最糟糕的情况,它表示不走索引全表扫描。我们应该尽量避免all。
8,Null。这是一种特殊情况。当前查询不需要查询表时,其type会是Null。比如获取系统
时间就不需要查询表,那么其执行计划显示的type就是Null。
我们对SQL语句的优化,需要达到 range 级别以上。
possible_keys字段:
这个是指查询中可能会用到的索引,不必特别关注。
key字段:
指实际查询中使用的索引,这个也不必特别关注。但是如果这个字段的值是Null,说明该查
询没有用到索引。一般来说,组合索引使用时如果不符合最左匹配,会出现“possible_keys"有
值,但”key"字段为空的情况。
Extra字段:
extra这个单词的意思是额外的。这里这个字段表示针对该查询干了哪些额外的事情,也是
一个比较重要的字段。关于这个字段的值,常用的是以下几个:
1,Using filesort。如果没有使用索引排序,而是使用了额外的排序规则,那么Extra就会
记录Using filesort。
2,Using temporary。tempoary的意思是临时工,它表示Mysql使用了临时表存储中间结
果。一般而言【
group by,distinct】之类的语句需要用到“临时工”。
3,Using index。它表示使用了覆盖索引。命中覆盖索引则不需要回表。另外,之前介绍索
引条件下推时也说到,索引条件下推时,extra字段的值也会是Using index。
4,Using where。它表示存储引擎返回数据后,server层使用where条件进行了数据筛选。
5,Select tables optimized away。这个表示没走到查询阶段就可以返回结果了。按官网
的说法,“在没有GROUP BY子句的情况下,基于索引优化MIN/MAX操作,或者对于MyISAM
存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成
优化。”
拿到数据后,最后一步就是返回数据给客户端了。Mysql采用的是一种即时返回的策略。它
不会等所有结果集就位后一起返回,而是从产生第一条结果时就开始返回数据到客户端。当然,
如果配置了缓存,结果会放到缓存里。返回数据是走网络,所以一个显而易见的结论是:传输的
数据越少返回越快。所以提取数据时,应该指明需要的字段,而不是无脑写“ * ”。
索引结构与调优 Mysql采用经过改良的B+树来存储索引数据。 B+树是一个加强版的B树,Mysql的B+树
与传统的B+树还不太一样,它有以下特征:
1,关键字个数等于路数。
2,InnoDB里,B+树节点不存储实际数据,所有数据放到最底层的叶子节点里。这些叶子
节点投影成了一个有序数组。
3,InnoDB里,每个叶子节点维护了一个指向它下一个叶子节点的指针,这样就形成了一个
双向链表。由于B树的叶子节点投影本身有序,这就成了一个有序的双向链表。这个有序链表对
范围查找非常友善,不需要再回到根节点重复IO。
4,这棵树的分叉非常多,使得这棵树的结构非常扁平。这样的结构能够在存储尽可能多的
树的同时,让IO次数尽可能少。假设这棵树只有三层,按每条数据1KB计算,大约有130万子节
点,能存储两千多万条数据。
5,存储数据时,需要进行子节点的分裂和合并重新调整。
整体结构如下:
根据以上结构,能推导出以下优化经验:
1,仅在需要的时候创建索引。索引再能满足需求的前提下,越少越好。一方面索引本身也
会占据不少的数据库资源(磁盘+内存),另一方面,在对数据进行增删改时,需要同步更新索
引树导致额外开销。
2,索引的字段要保证比较高的离散度。这是因为,如果一个字段的离散度太低,那么扫描
这颗B+树时就需要走更多的路数。当离散度低到一定程度时,甚至还不如直接走叶子节点扫全
表,这样至少能适用磁盘顺序读,比走索引更快。
3,创建联合需要符合最左匹配原则。对于联合索引,B+树上的键值也是从左往右构建和匹
配索引数据的。如果左边第一个命中,则直接按第一个走。未命中会继续走第二个,以此类推。
4,应用覆盖索引减少回表操作。根据上面的B+树结构可知,聚簇索引的叶子节点存储原始
数据。所以如果SQL的返回值刚好是索引值,那就不需要走叶子节点取数,直接在索引层就能返
回了。 5,有序ID减少页分裂。由于这棵B+树要保证叶子节点有序,所以如果插入了无序的ID,会
重新排列叶子节点。但如果数据本身有序,那么只需要顺序往后写即可,会更加高效。
6,查询条件里尽量不要有函数运算或子查询。索引树放在存储引擎层,只能做简单的逻辑
判断。如果写SQL时能保证逻辑简单,那这部分逻辑可以下推到存储引擎层,从而只返回符合条
件的数据。否则,只能用尽可能简单的方式扫描尽可能多的数据,再由执行引擎过滤掉不符合要
求的数据,导致性能低下。
SQL优化经验
其实,掌握了SQL的分析方法,优化方法也就出来了。有很多零零碎碎的优化经验,这里简
单列一些:
1,尽量避免在WHERE子句中使用函数,因为会使索引失效。
2,使用JOIN语句而不是子查询,因为JOIN语句更有效率。
3,确保表有适当的索引,以加快查询速度。
4,避免在SELECT语句中使用“*”,尽可能只选择需要的列。
5,尽量避免使用OR操作符,它会导致全表扫描而不是使用索引。
6,对于大型数据集,请考虑分区表或使用分页技术。
7,使用EXPLAIN语句来检查查询执行计划,找到问题并进行优化。
8,使用合适的数据类型,例如使用INT代替VARCHAR存储数字类型。
9,将多个单行查询组合成一个查询,以减少与数据库服务器的通信次数。
10,定期清理不再使用的索引和表,以保持数据库性能稳定。
个人经验和网传资料太过片面,想要系统掌握SQL优化的方法,还是建议看官网。以下是官
方提供的优化办法: https://dev.mysql.com/doc/refman/5.7/en/optimizing-innodb-loggin
g.html
Mysql使用基于开销的优化器,大多数时候它能够很好工作。如果查询优化器没有按预期的
方式工作,可以使用 FORCE INDEX 扫描表告诉 MySQL强制走索引。与使用给定索引相比,表
扫描非常昂贵: 1 SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
2 WHERE t1.col_name=t2.col_name;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/554264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows修改为Mac的字体方法

一: 首先下载字体文件和修改器 Mac字体修改 https://www.aliyundrive.com/s/KKvcRNYkP5p 提取码: 6d3p 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。 二: 设置并修改字体 1:…

服务(第二十八篇)rsync

配置rsync源服务器&#xff1a; #建立/etc/rsyncd.conf 配置文件 vim /etc/rsyncd.conf #添加以下配置项 uid root gid root use chroot yes #禁锢在源目录 address 192.168.80.10 …

浅谈管网抢维修效率对产销差率的影响

1 背景 多年来&#xff0c;漏损治理工作一直围绕检漏、分区计量或压力管理等相关话题&#xff0c;却忽视了抢维修速度与质量对漏损治理成效的影响。实际上&#xff0c;不管是DMA分区计量&#xff0c;还是检漏&#xff0c;最终还是要通过抢维修来修复漏点达到控制漏损的目的。尽…

Vue 3中利用UseStorage轻松实现本地存储功能,释放数据持久化的力量

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 一、介绍1.1 什么是本地存储1.2 Vue 3中的UseStorage插件简介 二、…

第18章_MySQL8其它新特性

第18章_MySQL8其它新特性 1. MySQL8新特性概述 MySQL从5.7版本直接跳跃发布了8.0版本&#xff0c;可见这是一个令人兴奋的里程碑版本。MySQL 8版本在功能上做了显著的改进与增强&#xff0c;开发者对MySQL的源代码进行了重构&#xff0c;最突出的一点是多MySQL Optimizer优化器…

MySQL-1-SQL语句的分类、MySQL命令、SQL查询语句

一、SQL语句的分类&#xff08;任何一条sql语句以分号结尾&#xff1b;SQL语句不区分大小写&#xff09; DQL&#xff08;数据查询语言&#xff09;&#xff1a;查询语句&#xff0c;凡是select都是DQL。 DML&#xff08;数据操作语言&#xff09;&#xff1a;insert、delete、…

Midjourney 介绍-AI绘画工具

《Midjourney》是一款2022年3月面世的AI绘画工具&#xff0c;创始人是David Holz。 它一款基于浏览器的在线应用程序&#xff0c;因此你无需安装任何软件&#xff0c;只需在浏览器中访问MidJourney的官方网站即可开始使用。 只要输入想到的文字&#xff0c;就能通过人工智能产出…

一文带你了解MySQL之基于成本的优化

前言 本文章收录在MySQL性能优化原理实战专栏&#xff0c;点击此处查看更多优质内容。 目录 一、什么是成本二、单表查询的成本2.1 准备数据2.2 基于成本的优化步骤2.3 基于索引统计数据的成本计算 三、连接查询的成本2.1 准备数据2.2 Condition filtering介绍2.3 多表连接的成…

『MySQL 实战 45 讲』16 - “order by” 是怎么工作的

“order by” 是怎么工作的 首先创建一个表 CREATE TABLE t ( id int(11) NOT NULL, city varchar(16) NOT NULL, name varchar(16) NOT NULL, age int(11) NOT NULL, addr varchar(128) DEFAULT NULL, PRIMARY KEY (id), KEY city (city) ) ENGINEInnoDB;全字段排序 在 cit…

正确甄别API、REST API、RESTful API和Web Service之间的异同

看到API你会想起什么&#xff1f;是接口、第三方调用、还是API文档&#xff1f;初看你可能会觉得这太熟悉了&#xff0c;这不是系统开发日常系列吗&#xff1f;但你仔细想一想&#xff0c;你会发现API的概念在你脑海里是如此的模糊。如何你通过搜索引擎检索API&#xff0c;你会…

目标检测数据预处理——部件截图,按一定比例进行外扩

本片是截图的篇的升级版本&#xff0c;简单版本的截图请参考根据目标框外扩一定比例进行截图&#xff08;连带标签&#xff09;。 对目标框&#xff08;类别名称&#xff09;进行分类&#xff0c;将同一类的目标框进行截图并分类保存在不同的文件夹中。 在本篇当中&#xff0c;…

Vue3中响应式Reactive的独特之处:它在哪些场景下胜出Ref?

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 一、Vue 3中响应式Reactive的独特之处1.1 引言1.2 Vue 3中的响应式…

算法leetcode|51. N 皇后(rust重拳出击)

文章目录 51. N 皇后&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 51. N 皇后&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以…

详解c++STL—STL常用算法

目录 1、常用遍历算法 1.1、for_each 1.2、transform 2、常用查找算法 2.1、find 2.2、find_if 2.3、adjacent_find 2.4、binary_search 2.5、count 2.6、count_if 3、常用排序算法 3.1、sort 3.2、random_shuffle 3.3、merge 3.4、reverse 4、常用拷贝和替换算…

在MyBatis XML文件中处理特殊符号的方法,如“>”、“<”、“>=”、“<=”这些符号XML会报错如何处理

前言 在MyBatis的XML映射文件中&#xff0c;我们经常需要使用特殊符号&#xff0c;比如"大于"、"小于"、"大于等于"、"小于等于"等比较操作符。然而&#xff0c;这些符号在XML中具有特殊的含义&#xff0c;因此需要进行特殊处理&…

nginx缓存及rsync远程访问控制

nginx缓存功能 http{ proxy_cache_path /data/nginx/cache/levels1:2 keys_zonemy_cache:10m max_size10g inactive60m use_temp_pathoff; path强制参数&#xff0c;指定缓存文件的存放路径。 levels: 定义了缓存目录的层级。每层可以用1(最多16种选择&#xff0c;0-f)或2(最…

2023年认证杯SPSSPRO杯数学建模A题(第一阶段)碳板跑鞋全过程文档及程序

2023年认证杯SPSSPRO杯数学建模 A题 碳板跑鞋 原题再现&#xff1a; 在专业运动鞋上使用的碳板&#xff0c;也可被称为碳纤维增强环氧树脂材料&#xff0c;事实上是将碳纤维织成布&#xff0c;再浸入环氧树脂固化后形成的板材。它以较轻的重量达到了相当好的弹性和刚度。在上…

【jvm系列-13】jvm性能调优篇---参数设置以及日志分析

JVM系列整体栏目 内容链接地址【一】初识虚拟机与java虚拟机https://blog.csdn.net/zhenghuishengq/article/details/129544460【二】jvm的类加载子系统以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963【三】运行时私有区域之虚拟机栈…

【腾讯云FinOps Crane 集训营】让我看看还有谁没用过crane这个降本利器

近几年云原生概念的发展如雨后春笋&#xff0c;势如破竹&#xff0c;而devops和k8s(Kubernetes)两兄弟也搭上云原生的车先后火了起来 devops&#xff1a;如字面意思Development&Operations&#xff0c;它的理念是开发即运维&#xff0c;目的是消除开发者们与运维之间的隔阂…

OpenCV:从 CMake 产生 VS2019 项目和解决方案

CMake 是一个跨平台的自动化编译程序&#xff0c;它用于管理代码的构建过程。使用 CMake 可以简化跨平台项目的构建和移植&#xff0c;提供简单而强大的语法来描述构建过程&#xff0c;并生成多种不同的构建系统&#xff0c;如 GNU Make、Ninja 和 Visual Studio。因为 CMake 具…