Sql优化

以MySQL DBMS - MySQL Database Management System(数据库管理系统)为例
测试数据量300w+

不同方案效率对比

一、测试数据导入

1.新建数据库sql_optimization,设置字符集utf8
在这里插入图片描述

2.导入数据(SQL文件在01资料/01 三百万测试数据中)
在这里插入图片描述
3.导入结果查看
在这里插入图片描述

二、使用不同引擎执行时间

1.直接进行查询后执行时间
在这里插入图片描述
2.修改表的引擎为MyISAM后结果
2.1 右键表 -> 设计表
在这里插入图片描述
2.2 选择 选项 -> 修改引擎为MyISAM -> 保存
在这里插入图片描述
2.3 执行查询全部语句后,观察执行时间
在这里插入图片描述
3.通过上面两种不同的引擎可以看出300w数据量时间差在秒级以上,这对于现在的毫秒级服务器,微妙级服务器,甚至纳秒级服务器来说是不能接受的。
三、测试查询语句结果
1.如果查询时使用查询全部的*进行查询
在这里插入图片描述
2.只查询一列
在这里插入图片描述

MySQL优化

一.MySQL 优化简介
1.MySQL官方给出优化(Optimization)的解决方案
https://dev.mysql.com/doc/refman/5.7/en/optimization.html

2.优化MySQL主要从两个方向:硬件级别(Hardware Level)、数据库级别(Database Level)

3.硬件级别瓶颈包含如下的几个方面

3.1 磁盘寻找(Disk seeks):磁盘需要一段时间才能找到一段数据。对于现代磁盘来说,这种平均时间通常低于10ms,因此理论每秒100次寻找。这一次用新的磁盘缓慢地改进,并且对于单个表是很难优化的。优化查找时间的方法是将数据分发到一个以上的磁盘上。

3.2 磁盘读写(Disk reading and writing)。当磁盘处于正确位置时,我们需要读取或写入数据。使用现代磁盘,一个磁盘可以提供至少10到20Mb/s的吞吐量。这比磁盘寻找更容易优化,因为您可以从多个磁盘并行读取。

3.3 CPU(CPU cycles)。当数据在主存储器中时,我们必须处理它以得到结果。与内存量相比,具有大数据库量的表是最常见的限制因素。但是对于小表来说,速度通常不是问题。

3.4 存储带宽(Memory bandwidth)。当CPU需要比CPU缓存中更多的数据时,主存储器带宽成为瓶颈。对于大多数系统来说,这是一个不常见的瓶颈,但也是一个需要注意的点

  1. 数据库级别:导致数据库应用最高效的因素是它的基本设计

4.1 表结构是否正确(Are the tables structured properly?):特别的是列是否具有正确的类型,和表中列的个数是否正确。例如:对于执行频繁更新的应用通常设计更多表,每个表的列并不多。而对于需要进行大量分析的应用通常设计更少的表,而每个表的列更多一些。

4.2 正确的设置索引达到查询高效(Are the right indexes in place to make queries efficient?):需要考虑的是什么SQL会导致索引无效,什么情况会让查询效率更高

4.3 对于不同情况选择不同的存储引擎(Are you using the appropriate storage engine for each table, and taking advantage of the strengths and features of each storage engine you use? )选择不同的存储引擎对性能和可伸缩性具有较大的影响

4.4 每张表是否具有适当的行格式(Does each table use an appropriate row format?):主要取决于适当的存储引擎。压缩表可以占用更低的磁盘空间和更少的I/O操作。压缩表适用于InnoDB和MyISM存储引擎。

4.5 应用程序是否使用适当的锁策略(Does the application use an appropriate locking strategy? ):在具有高并发、分布式应用程序中,选择适当的锁策略以保证数据的共享性和特定的情况下独占数据。InnoDB存储引擎在不需要我们参与下能处理大部分锁问题,允许数据库实现更好的并发性,减少代码调优量。

4.6 所有缓存区域使用的大小是否都正确(Are all memory areas used for caching sized correctly?):配置的原则是缓存区域大到足以容纳所有频繁访问的数据,但又不能太大,否则导致过量占用物理内存而导致分页。一般情况下需要配置InnoDB的缓冲池、MyISAM密钥缓存和MySQL的查询缓存

二、 优化的哲学
注意:优化有风险,涉足需谨慎!
1.优化可能带来的问题
1.1 优化不总是对一个单纯的环境进行,还很可能是一个复杂的已投产的系统。
1.2 优化手段本来就有很大的风险,只不过你没能力意识到和预见到!
1.3 任何的技术可以解决一个问题,但必然存在带来一个问题的风险!
1.4 对于优化来说解决问题而带来的问题,控制在可接受的范围内才是有成果。
结论:保持现状或出现更差的情况都是失败!
2.优化的需求
2.1 稳定性和业务可持续性,通常比性能更重要!
2.2 优化不可避免涉及到变更,变更就有风险!
2.3 优化使性能变好,维持和变差是等概率事件!
2.4 切记优化,应该是各部门协同,共同参与的工作,任何单一部门都不能对数据库进行优化!
结论:所以优化工作,是由业务需要驱使的!!!
四、优化由谁参与
在进行数据库优化时,应由数据库管理员、业务部门代表、应用程序架构师、应用程序设计人员、应用程序开发人员、硬件及系统管理员、存储管理员等,业务相关人员共同参与。
五、优化的顺序
优化选择:
优化成本:硬件>系统配置>数据库表结构>SQL及索引
优化效果:硬件<系统配置<数据库表结构<SQL及索引
六、常见优化工具
检查问题常用工具:
在这里插入图片描述
不常用但好用的工具:
在这里插入图片描述
**

MySQL 架构

**
一.架构
想要学习好SQL优化就必须从对应数据库的基本架构开始学习
1.架构图如下
在这里插入图片描述
二.架构分析
1.连接管理与安全验证:MySQL有连接池(Connection Pool)管理客户端的连接。客户端连接后会验证用户名、密码、主机信息等
2.缓存(Cache&Buffer):缓存中存储了SQL命令的HASH,直接比对SQL命令的HASH和缓存中key是否对应,如果对应,直接返回结果,不再执行其他操作。由于缓存的是SQL的HASH,所以根据Hash特性SQL中空格等内容必须完全一样。缓存里面包含表缓存、记录缓存、权限缓存等。查询语句执行完成后会把查询结果缓存到缓存中。
2.1在MySQL 5.7 中查询缓存默认不开启。可以通过
SHOW VARIABLES LIKE ‘%query_cache%’;
2.2参数中query_cache_type设置是否开启查询缓存。
2.2.1 0(OFF):关闭 Query Cache 功能,任何情况下都不会使用 Query Cache;
2.2.2 1(ON):开启 Query Cache 功能,但是当SELECT语句中使用SQL_NO_CACHE提示后,将不使用Query Cache;
2.2.3 2(DEMAND):开启Query Cache 功能,但是只有当SELECT语句中使用了SQL_CACHE 提示后,才使用Query Cache。
2.2.4 可以通过修改my.ini或命令设置是否开启查询缓存(此命令在Navicat中可能不可用,可以去命令行设置)
set global query_cache_type = 1;
2.3 query_cache_size设置查询缓存大小。默认为0
在这里插入图片描述
2.3.1 可以通过下面命令设置。如果设置值太小会导致查询缓存不可用。
SET GLOBAL query_cache_size=134217728;
2.3可以通过查看缓存被使用次数查看是否使用缓存。
SHOW STATUS like ‘%Qcache%’;
2.3.1 Qcache_queries_in_cache 当前缓存中数量
2.3.2 Qcache_insert 插入到缓存中总数
2.3.3 Qcache_hits 缓存命中数
2.3.4 Qcache_lowmem_prunes 由于缓存较小,从缓存中删除的查询数量
2.3.5 Qcache_not_cached 没有被缓存的次数
在这里插入图片描述
2.4查看on情况下增加一次的sql
select title from test where id=1;
3.解析器(Parser)主要作用是解析SQL命令。将SQL命令分解成数据结构(解析树),后续的操作都是基于这个结构的。如果在分解过程中遇到错误,出现SQL解析错误。解析时主要检查SQL中关键字,检查关键字是否正确、SQL中关键字顺序是否正确、引号是否对应是否正确等。
4.预处理器:根据解析器的解析树,进一步检查表是否存在、列是否存在、名字和别名是否有歧义等。
5.优化器(Optimizer):根据官网说明在执行SQL查询时会根据开销自动选择最优查询方案。采用“选择-投影-连接”的策略。先选择where中的行数。同时先选择要选择的列,而不是全部列,最后把内容合并到一起。
6.执行器:包含执行SQL命令。获取返回结果。生成执行计划等。
7.存储引擎:访问物理文件的媒介
三.SQL命令执行流程
1.客户端向服务器端发送SQL命令
2.服务器端连接模块连接并验证
3.缓存模块解析SQL为Hash并与缓存中Hash表对应。如果有结果直接返回结果,如果没有对应继续向下执行
4.解析器解析SQL为解析树,如果出现错误,报SQL解析错误。如果正确,向下传递
5.预处理器对解析树继续处理,处理成新的解析树。
6.优化器根据开销自动选择最优执行计划,生成执行计划
7.执行器执行执行计划,访问存储引擎接口
8.存储引擎访问物理文件并返回结果
9.如果开启缓存,缓存管理器把结果放入到查询缓存中。
10.返回结果给客户端

存储引擎

一.MySQL数据库引擎简介
1.ISAM(Indexed Sequential Access Method)
ISAM是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数据库被查询的次数要远大于更新的次数。因此,ISAM执行读取操作的速度很快,而且不占用大量的内存和存储资源。ISAM的两个主要不足之处在于,它不支持事务处理,也不能够容错。如果你的硬盘崩溃了,那么数据文件就无法恢复了。如果你正在把ISAM用在关键任务应用程序里,那就必须经常备份你所有的实时数据,通过其复制特性,MYSQL能够支持这样的备份应用程序。
注意:使用ISAM注意点:必须经常备份所有实时数据。
版本:MySQL 5.7不支持ISAM
2.MyISAM
MyISAM是MySQL的ISAM扩展格式(MySQL5.5之前版本的缺省数据库引擎)数据库引擎。除了提供ISAM里所没有的索引和字段管理的大量功能,MyISAM还使用一种表格锁定的机制,来优化多个并发的读写操作,其代价是你需要经常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的空间。MyISAM还有一些有用的扩展,例如用来修复数据库文件的MyISAMCHK工具和用来恢复浪费空间的 MyISAMPACK工具。MYISAM强调了快速读取操作,这可能就是为什么MySQL受到了WEB开发如此青睐的主要原因:在WEB开发中你所进行的大量数据操作都是读取操作。所以,大多数虚拟主机提供商和INTERNET平台提供商只允许使用MYISAM格式。MyISAM格式的一个重要缺陷就是不能在表损坏后恢复数据。
MyISAM引擎使用注意:必须经常使用Optimize Table命令清理空间;必须经常备份所有实时数据。工具有用来修复数据库文件的MyISAMCHK工具和用来恢复浪费空间的 MyISAMPACK工具。不支持事务。数据越多,写操作效率越低。因为要维护数据和索引信息。(索引列越多,相对效率越低。)
2.1 如果使用该数据库引擎,会生成三个文件:
.frm:表结构信息
.MYD:数据文件
.MYI:表的索引信息
3.InnoDB
InnoDB数据库引擎都是造就MySQL灵活性的技术的直接产品,这项技术就是MYSQL++ API。在使用MySQL的时候,你所面对的每一个挑战几乎都源于ISAM和MyISAM数据库引擎不支持事务处理(transaction process)也不支持外键。尽管要比ISAM和MyISAM引擎慢很多,但是InnoDB包括了对事务处理和外键的支持,这两点都是前两个引擎所没有的。是现在的MySQL(5.5以上版本)常用版本默认引擎,也是默认的存储引擎。
MySQL 官方对InnoDB是这样解释的:InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读,这些特色增加了多用户部署的性能。没有在InnoDB中扩大锁定的需要,因为在InnoDB中行级锁定适合非常小的空间。InnoDB也支持FOREIGN KEY强制。在SQL查询中,你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也可以混合。
InnoDB是为处理巨大数据量时的最大性能设计,它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。
InnoDB存储引擎被完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。这与MyISAM表不同,比如在MyISAM表中每个表被存在分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上。
在MySQL5.7版本中,InnoDB存储引擎管理的数据文件为两个:分别是frm,idb文件。
InnoDB特点:
1)、支持事务
2)、数据多版本读取(InnoDB+MyISAM+ISAM)
3)、锁定机制的改进
4)、实现外键
3.1 InnoDB与MyISAM区别

  1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin transaction和commit之间,组成一个事务;
  2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MyISAM会失败;
  3. InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
  4. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
  5. InnoDB不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;5.7 已经支持
    3.2 如何选择
  6. 是否要支持事务,如果是选择InnoDB,如果不需要可以考虑MyISAM
  7. 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读写也挺频繁,请使用InnoDB。
  8. 系统崩溃后,MyISAM恢复起来更困难,能否接受;
  9. MySQL5.5版本开始InnoDB已经成为MySQL的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。
    4.Memory存储引擎
    Memory存储引擎,通过名字就很容易让人知道,他是一个将数据存储在内存中的存储引擎。Memory存储引擎不会将任何数据存放到磁盘上,仅仅存放了一个表结构相关信息的.frm文件在磁盘上面。所以一旦MySQL Crash或者主机Crash之后,Memory的表就只剩下一个结构了。Memory表支持索引,并且同时支持Hash和B-Tree两种格式的索引。由于是存放在内存中,所以Memory都是按照定长的空间来存储数据的,而且不支持BLOB和TEXT类型的字段。Memory存储引擎实现页级锁定。
    5.NDBCluster存储引擎
    NDB存储引擎也叫NDBCluster存储引擎,主要用于MySQL Cluster分布式集群环境,Cluster是MySQL从5.0版本才开始提供的新功能。
    6.MRG_MYISAM存储引擎
    在以前叫做MERGE,MySQL 5.7中叫做MRG_MYISAM
    MERGE存储引擎,在MySQL用户手册中也提到了,也被大家认识为MRG_MyISAM引擎。Why?因为MERGE存储引擎可以简单的理解为其功能就是实现了对结构相同的MyISAM表,通过一些特殊的包装对外提供一个单一的访问入口,以达到减小应用的复杂度的目的。要创建MERGE表,不仅仅基表的结构要完全一致,包括字段的顺序,基表的索引也必须完全一致。BDB存储引擎
    BDB存储引擎全称为BerkeleyDB存储引擎,和Innodb一样,也不是MySQL自己开发实现的一个存储引擎,而是由SleepycatSoftware所提供,当然,也是开源存储引擎,同样支持事务安全。
    7.FEDERATED存储引擎
    FEDERATED存储引擎所实现的功能,和Oracle的DBLINK基本相似,主要用来提供对远程MySQL服务器上面的数据的访问接口。如果我们使用源码编译来安装MySQL,那么必须手工指定启用FEDERATED存储引擎才行,因为MySQL默认是不起用该存储引擎的。
    8.ARCHIVE存储引擎
    ARCHIVE存储引擎主要用于通过较小的存储空间来存放过期的很少访问的历史数据。ARCHIVE表不支持索引,通过一个.frm的结构定义文件,一个.ARZ的数据压缩文件还有一个.ARM的meta信息文件。由于其所存放的数据的特殊性,ARCHIVE表不支持删除,修改操
    作,仅支持插入和查询操作。锁定机制为行级锁定。
    9.BLACKHOLE存储引擎
    BLACKHOLE存储引擎是一个非常有意思的存储引擎,功能恰如其名,就是一个“黑洞”。就像我们unix系统下面的“/dev/null”设备一样,不管我们写入任何信息,都是有去无回。
    10.CSV存储引擎
    CSV存储引擎实际上操作的就是一个标准的CSV文件,他不支持索引。起主要用途就是大家有些时候可能会需要通过数据库中的数据导出成一份报表文件,而CSV文件是很多软件都支持的一种较为标准的格式,所以我们可以通过先在数据库中建立一张CSV表,然后将生成的报表信息插入到该表,即可得到一份CSV报表文件了。
    11.PERFORMANCE_SCHEMA存储引擎
    从MySQL 5.6 开始新增的PERFORMANCE_SCHEMA数据库的存储引擎是PERFORMANCE_SCHEMA,PERFORMANCE_SCHEMA在之前版本中就有,主要用于收集一些系统参数。
    二.存储引擎管理
    1.查看数据库支持的存储引擎
    show engines
    2.查看数据库当前使用的存储引擎
    就是默认引擎是什么。
    show variables like ‘%storage_engine%’
    也可以在MySQL配置文件中查看。 windows - my.ini。 Linux - my.cnf
    3.查看数据库表所用的存储引擎
    show create table table_name
    4.创建表指定存储引擎
    create table table_name (column_name column_type) engine = engine_name
    5.修改表的存储引擎
    alter table table_name engine=engine_name
    6.修改默认的存储引擎
    在MySQL配置文件中修改下述内容:
    default-storage-engine=INNODB
    MySQL配置文件:
    windows系统 - 5.7版本my.ini文件在数据目录中。 C:\ProgramData\MySQL\MySQL Server 5.7
    linux系统 - /etc/my.cnf

SQL优化

一、SQL优化简介

  1. 解释:对于特定的要求,使用更优的SQL策略或索引策略,以达到让结果呈现的时间更短,从而提升操作效率的过程就是SQL优化。
  2. SQL 优化包含在数据库级别优化中。我们平常所说的SQL优化就是指优化SQL语句和索引
  3. SQL优化是是伴随着业务而进行优化的,并不是下面的所有操作就必须都达到才是好的优化。
    二、常规调优思路(众多解决方案之一)
    1、查看slow-log,分析slow-log,分析出查询慢的语句。
    2、按照一定优先级,进行一个一个的排查所有慢语句。
    3、分析top sql,进行explain调试,查看语句执行时间。
    4、调整索引或语句本身。

MySQL日志支持

一、MySQL 5.7中日志分类
1.MySQL 中日志分为四类:错误日志(回滚等)、二进制日志(主从)、通用查询日志(记录查询等信息)、慢查询日志
二、通用查询日志
1.通用查询日志是记录建立的客户端连接和执行的语句
2.通过show variables like ‘%version%’;查看版本信息
在这里插入图片描述
3.可以通过show variables like ‘%general%’ 查看通用查询日志是否开启
3.1.general_log 属性取值
3.1.1.OFF 表示关闭(默认关闭)
3.1.2.ON 表示打开
在这里插入图片描述
4.通过查看日志输出格式
4.1.FILE 存储在数数据库的数据文件中的 主机名.log
4.1.1.C:\ProgramData\MySQL\MySQL Server 5.7\Data
4.2.TABLE 存储在数据库中的mysql/general_log
在这里插入图片描述
5.临时开启/关闭通用日志(重启失效)

开启

set global general_log=on;

关闭

set global general_log=off;
在这里插入图片描述
6.临时设置输出格式(重启失效)

mysql/general_log

set global log_output=‘TABLE’;

主机名-slow.log

set global log_output=‘FILE’;

两者都输出

set global log_output=‘FILE,TABLE’;
在这里插入图片描述
7.永久设置。修改MySQL配置文件
7.1. windows中日志文件在C:\ProgramData\MySQL\MySQL Server 5.7\my.ini中。
7.2.按需配置
在这里插入图片描述
7.3.配置后重启MySQL 服务
8.日志文件中时间和系统时间不一致问题
8.1.查看系统日志文件格式
show variables like ‘%log_timestamps%’;
8.2.修改日志文件时间格式为系统时间
set global log_timestamps = SYSTEM

三、错误日志
1.MySQL 错误日志记录MySQL运行过程中较为严重的警告和错误信息,以及MySQL启动和关闭的详细信息。
2.通过show variables like ‘%log_error%’;查看
2.1.binlog_error_action 错误处理方式
2.1.1.ABORT_SERVER 出现问题终止服务
2.1.2.IGNORE_ERROR 忽略错误
2.2.log_error 错误日志文件名及路径
2.3.log_error_verbosity 记录级别
2.3.1.取值1表示记录警告信息
2.3.2.大于1表示所有警告信息都记录
在这里插入图片描述
3.日志文件可以通过文本编辑器打开。
四、二进制日志
1.包含所有更新数据(新增、删除、修改、改表等)SQL 信息的记录。
2.MySQL 主从配置就依赖这个日志文件
3.通过show variables like ‘%log_bin%’;查看二进制
在这里插入图片描述
4.二进制日志不可以通过修改全局参数开启。全局配置文件(my.ini)中该参数是注释的。
在这里插入图片描述
直接设置log-bin的值为日志文件名。
在这里插入图片描述
设置后重启MySQL服务会发现log_bin参数值为ON
在这里插入图片描述
5.开启后二进制文件存储在C:\ProgramData\MySQL\MySQL Server 5.7\Data。里面有个xxx.index文件(这个文件称为二进制文件索引)里面存储了所有二进制文件清单。当重启MySQL服务或过一定时间后会自动增加一个二进制文件。增加的二进制文件编号递增。也可以使用flush logs;命令生成一个新的二进制文件。
6.也可以通过命令:show binary logs;查看目前生成的日志文件
7.由于是二进制文件,所以无法直接使用文本编辑器打开。需要借助工具才可以看见。
7.1 在navicat或sql命令中输入
show binlog events in ‘mylogbin.000003’;
7.2 在命令行输入,借助mysqlbinlog工具
7.2.1 输入命令时要在日志文件所在文件夹路径中运行,也可以在命令中写上日志文件的全路径
7.2.2 > D:/a.sql 可以没有,没有表示直接打印到控制台
mysqlbinlog mylogbin.000003 > D:/a.sql

8.binlog中除了删除表、创建表的SQL都是加密的,如果希望看见可以使用下面命令
8.1 直接打印到控制台会出现中文乱码
mysqlbinlog --base64-output=decode-rows -v mylogbin.000003 > D:/a.sql

五、慢查询日志
1.记录所有执行时间超过long_query_time秒的所有查询或不适用于索引的查询
2.long_query_time默认时间为10秒。即超过10秒的查询都认为是慢查询
3.慢查询日志默认名称:主机名-slow.log
在这里插入图片描述
4.除了查看my.ini文件以外通过show variables like ‘%quer%’;查看
4.1.slow_query_log 表示是否开启慢查询日志。(默认开启)
4.2.slow_query_log_file 慢查询日志文件名
4.3.long_query_time 慢查询阈值设置,查出为慢查询。此值直接设置全局参数可能无效,建议测试时直接修改配置文件。
4.4.log_queries_not_using_indexes 是否记录不适用于索引的查询(前提slow_query_log开启)
在这里插入图片描述
5.可以通过命令查看慢查询日志中慢查询SQL命令的个数。也可以使用文本编辑器直接打开慢查询日志文件。也可以查看mysql.slow_log表中数据(前提log_output值包含table)
show status like “%slow_queries%”;

执行计划

一.explain
1.执行计划:在MySQL中可以通过explain关键字模拟优化器执行SQL语句,从而知道MySQL是如何处理SQL语句的。
2.explain:MySQL执行计划的工具,查看MySQL如何设定执行计划
3.老版本MySQL中explain分为两类(在MySQL5.7中已经不在区分)
3.1.explain extended:会在 explain 的基础上额外提供一些查询优化的信息。紧随其后通过 show warnings 命令可以 得到优化后的查询语句,从而看出优化器优化了什么。额外还有 filtered 列,是一个半分比的值,rows * filtered/100 可以估算出将要和 explain 中前一个表进行连接的行数(前一个表指 explain 中的id值比当前表id值小的表)。
3.2.explain partitions:相比 explain 多了个 partitions 字段,如果查询是基于分区表的话,会显示查询将访问的分区。
4.使用语法:
4.1.在查询语句之前添加explain即可(默认:explain partitions)
在这里插入图片描述
4.2 紧跟show warnings可以查看优化器优化效果(两条SQL语句要一起执行)
在这里插入图片描述
5.使用show warnings很有必要,explain是按照优化器优化后的记过进行显示的。
二.explain 字段解释
给定表结构
create table teacher (
id int primary key auto_increment,
name varchar(20)
);

insert into teacher values(1,‘老师1’);
insert into teacher values(2,‘老师2’);
insert into teacher values(3,‘老师3’);

create table student(
id int primary key auto_increment,
name varchar(20),
tid int,
constraint fk_tea_stu foreign key (tid) REFERENCES teacher(id)
);

insert into student values(1,‘学生1’,1);
insert into student values(2,‘学生1’,2);
insert into student values(3,‘学生1’,2);
insert into student values(4,‘学生1’,3);
insert into student values(5,‘学生1’,3);
insert into student values(6,‘学生1’,3);
1.id : 查询执行顺序
1.1. id值相同时表示从上向下执行
1.2. id值相同被视为一组
1.3. 如果是子查询,id值会递增,id值越高,优先级越高
2.select_type : 查询类型,主要用于区分普通查询、联合查询、子查询等
2.1 SIMPLE:简单查询,只要不是子查询和union都属于简单查询
explain select * from teacher where id=5;
2.2 PRIMARY:复杂查询中最外层查询。
explain select * from (select * from student limit 0,1) t;
2.3 DERIVED(衍生):from从句中的子查询。
explain select * from (select * from student limit 0,1) t;
2.4 SUBQUERY:在select或where从句中包的子查询
explain select * from student where id = (select id from student limit 0,1);
explain select *,(select id from student where id=3) from student ;
show warnings;
2.5 UNION:分为如下几种情况
2.5.1 两个select查询时前一个标记为PRIMARY,后一个标记为UNION
explain select * from student where id = 1 or id = 2
union
select * from student where id = 2 or id = 3 or id = 4;
2.5.2 union出现在from从句子查询中,外层select标记为PIRMARY,union中第一个查询为DERIVED,第二个子查询标记为UNION
explain select * from (select * from student where id = 1 or id = 2
union
select * from student where id = 2 or id = 3 or id = 4) ut;
2.6 UNION RESULT:从union表获取结果的select
3.partitions:如果查询是基于分区表的话,会显示查询将访问的分区。
4.table : 查询的哪个表
5.type :查询类型,SQL优化中非常重要的指标。
5.1.从好到坏排序。一般要求至少是range级别,最好能达到ref级别
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
5.2.system:表中只有一行数据。属于const的特例。如果物理表中就一行数据为ALL
explain select * from (select * from student limit 0,1) t;
5.3.const:查询结果最多有一个匹配行。因为只有一行,所以可以被视为常量。const查询速度非常快,因为只读一次。一般情况下把主键或唯一索引作为唯一条件的查询都是const
explain select * from teacher where id = 55
5.4.eq_ref: 查询时查询外键表全部数据。且只能查询主键列或关联列。且外键表中外键列中数据不能有重复数据,且这些数据都必须在主键表中有对应数据(主键表中数据可以有没有用到的)
create table a(
id int(10) primary key auto_increment,
name varchar(20)
);
create table b(
id int(10) primary key auto_increment,
name varchar(20),
aid int(10),
CONSTRAINT a_b foreign key (aid) REFERENCES a(id)
);
insert into a values (1,‘a1’);
insert into a values (2,‘a2’);
insert into a values (3,‘a3’);
insert into a values(4,‘a4’);
insert into b values(1,‘b1’,1);
insert into b values(2,‘b2’,2);
insert into b values(3,‘b3’,3);
insert into b values(4,‘b4’,4);
explain select a.id,b.id,b.aid from b,a where b.aid=a.id ;
5.5.ref:相比 eq_ref,不对外键列有强制要求,里面的数据可以重复,只要出现重复的数据取值就是ref。也可能是索引查询。
5.6.range:把这个列当作条件只检索其中一个范围。常见where从句中出现between、<、in等。主要应用在具有索引的列中
explain select * from student where id between 1 and 5
5.7.index:Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常为ALL块,因为索引文件通常比数据文件小。(Index与ALL虽然都是读全表,但index是从索引中读取,而ALL是从硬盘读取)
5.8.ALL:Full Table Scan,遍历全表以找到匹配的行
6.possible_type : 查询条件字段涉及到的索引,可能没有使用
7.key:实际使用了的索引
8.key_len:表示索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。key_len是根据表定义计算而得的,不是通过表内检索出的
9.ref:显示索引的哪一列被使用了,如果可能,是一个常量const。
10.rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
11.fitered:显示了通过条件过滤出的行数的百分比估计值。
12.Extra: 不适合在其他字段中显示,但是十分重要的额外信息
12.1.Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
12.2.Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
12.3.range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
12.4.Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。
12.5.Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
12.6.Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。
12.7.Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
12.8.Using sort_union(…), Using union(…), Using intersect(…):这些函数说明如何为index_merge联接类型合并索引扫描。
12.9.Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。

MySQL中索引

一、索引概述
1.索引的优点
为什么要创建索引?这是因为,创建索引可以大大提高系统的查询性能。 如果不使用索引,查询时从第一行开始查询。如果使用了索引就可以更加快速的找到希望的数据
第一、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二、可以大大加快 数据的检索速度,这也是创建索引的最主要的原因。
第三、可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四、在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五、通过使用索引,可以在查询的过程中,使用查询优化器,提高系统的性能。
2.索引的缺点
也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?这种想法固然有其合理性,然而也有其片面性。虽然,索引有许多优点, 但是,为表中的每一个列都增加索引,是非常不明智的。 这是因为,增加索引也有许多不利的一个方面:
第一、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二、索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。
第三、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
3.什么样的字段适合创建索引
索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。 一般来说,应该在具备下述特性的列上创建索引:
第一、在经常需要搜索的列上,可以加快搜索的速度;
第二、在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
第三、在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
第四、在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
第五、在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
第六、在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
建立索引,一般按照select的where条件来建立,比如: select的条件是where f1 and f2,那么如果我们在字段f1或字段f2上建立索引是没有用的,只有在字段f1和f2上同时建立索引才有用等。
4.什么样的字段不适合创建索引:
同样,对于有些列不应该创建索引。一般来说,不应该创建索引的这些列具有下述特点:
第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
二、 MySQL中的索引种类

  1. 单列索引。就是给一个列添加索引。
    1.1 普通索引:不考虑过多情况,主要是为了让查询更快一些。
    1.2 唯一索引:列中值不可以重复,可以是null
    1.3 主键索引:列中值不可以重复,又不可以为null
  2. 组合索引。给表中大于等于两个列添加索引。但是需要满足最左前缀
  3. 全文索引(full-text)
    3.1 只能在MyISAM存储引擎才可以使用
    3.2 只能在char、varchar、text等字段才可以使用全文索引
    3.3 全文索引是抽取一列内容的关键字,通过关键字建立索引。例如:我们都在尚学堂学习。当搜索尚学堂时就可以搜索这句话。所以全文所以适用于含有like的查询。但是也只能解决‘xxxx%’模糊查询低效的问题。
    三、MySQL中的索引管理
    建立索引可以在建立表时直接指定索引,也可以后期添加索引(在本套课程中只讲解如何后期添加索引)。且要注意主键约束具有自动带有主键索引,唯一约束自动带有唯一索引。
    在MySQL中,对索引的查看和删除操作是所有索引类型通用的。
    1.普通索引
    这是最基本的索引,它没有任何限制MyIASM中默认的BTREE类型的索引,也是我们大多数情况下用到的索引。
    1.1.创建索引
    CREATE INDEX index_name ON table_name (column(length))
    ALTER TABLE table_name ADD INDEX index_name (column(length))
    CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id) , INDEX index_name (title(5)))
    show index from test;
    create index normal_index on test(title);

查看执行计划后,直观感受查询时间

explain select * from test where title=‘正负零 0’;
1.2.查看索引
SHOW INDEX FROM [table_name]
SHOW KEYS FROM [table_name] # 只在MySQL中可以使用keys关键字。
1.3.删除索引
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY
2.唯一索引
与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似
2.1.创建索引
CREATE UNIQUE INDEX index_name ON table_name (column(length))
ALTER TABLE table_name ADD UNIQUE index_name (column(length))
CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id) , UNIQUE index_name (title(length)))
create unique index unique_index on teacher(name);
explain select * from teacher where name=‘老师3’;
drop index unique_index on teacher;
3.全文索引(FULLTEXT)
MySQL从3.23.23版开始支持全文索引和全文检索,FULLTEXT索引在MySQL5.6之前仅可用于 MyISAM 表,在MySQL5.7后InnoDB也支持;他们可以从CHAR、VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或CREATE INDEX被添加。
对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引,其速度比把资料输入现有FULLTEXT索引的速度更为快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
全文索引对中文支持不好,如果搜索中文就只能按照最左对照进行搜索。如果是英文就可以匹配中间
3.1.创建索引
CREATE FULLTEXT INDEX index_name ON table_name(column(length))
ALTER TABLE table_name ADD FULLTEXT index_name( column)
CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id) , FULLTEXT index_name (title))
3.2 创建后的全文索引需要配合match(列,列) against(‘内容’)使用。
3.2.1 match中列必须和创建全文索引的列一样。例如创建全文索引时(id,name),match(name)无法使用全文索引,必须单独建立name列的全文索引
alter table teacher add column (address varchar(200));
update teacher set address=‘北京海淀’
create fulltext index full_index3 on teacher(name,address);
explain select * from teacher where match(address) against(‘北京’);
drop index full_index3 on teacher;
3.2.2 against中内容有三种模式
3.2.2.1 自然语言模式:IN NATURAL LANGUAGE MODE
3.2.2.2 布尔模式:IN BOOLEAN MODE
3.2.2.3 查询扩展模式:WITH QUERY EXPANSION
3.3 自然语言模式:
update teacher set address =‘北京昌平’ where id=2;
update teacher set address =‘北京丰台’ where id=3;
create fulltext index full_index_address on teacher(address);
show index from teacher;
select * from teacher;

北京昌平可以查询到,但是北京无法查询到

explain select * from teacher where match(address) against(‘北京昌平’ in natural language mode);
3.4 布尔模式:支持特殊符号。及时对没有全文索引的列也可以进行搜索,但是非常慢。查询时必须从最左开始查询,例如:北京昌平,按照昌平无法查询
3.4.1 + 一定要有(不含有该关键词的数据条均被忽略)。
3.4.2 - 不可以有(排除指定关键词,含有该关键词的均被忽略)。
3.4.3 > 提高该条匹配数据的权重值。
3.4.4 < 降低该条匹配数据的权重值。
3.4.5 ~ 将其相关性由正转负,表示拥有该字会降低相关性(但不像 - 将之排除),只是排在较后面权重值降低。
3.4.6 * 万用字,不像其他语法放在前面,这个要接在字符串后面。
3.4.7 " " 用双引号将一段句子包起来表示要完全相符,不可拆字。

查询北京*可以,但是北京、昌平不可以

explain select * from teacher where match(address) against(‘北京*’ in boolean mode);
3.5 查询扩展。查询时进行扩展查询,发现和条件有关系的内容都查询出来
update teacher set address=‘oracle beijing changping’ where id=1;
update teacher set address=‘haidian fengtai beijing’ where id=2;
update teacher set address=‘oracle is a database’ where id=3;

只能查询两行

explain select * from teacher where match(address) against(‘beijing changping’ in natural language mode);

查询到三行,因为oracle出现在beijing changping同行,查询时认为oracle和beijing changping有关,所以按照oracle进行查询

explain select * from teacher where match(address) against(‘beijing changping’ with query EXPANSION);
3.1中文拆词器ngram
由于中文是没有空格的,MySQL 从5.7.6开始内置ngram中文分词插件。可以设置把整个中文按照指定大小进行拆词。
1.在my.ini中[mysqld]下添加参数,设置拆词长度
ngram_token_size=2

2.建立表,插入数据
create table ft (
id int primary key auto_increment,
name varchar(20),
address varchar(200)
);
insert into ft values(1,‘张三’,‘北京市昌平区建材城85号院’);
insert into ft values(2,‘李四’,‘上海市虹桥机场’);
insert into ft values(3,‘王五’,‘河北省保定市’);
insert into ft values(4,‘赵六’,‘中华人民共和国北京市海淀区’);
3.给address创建全文索引。注意后面的with parser ngram
create fulltext index index3 on ft(address) with parser ngram;
4.查看是否已经对ft表保存索引信息。如果没有,设置ft中索引保存到索引表中
4.1 修改的前提是,这个表有全文索引
show variables like ‘%innodb_ft_aux_table%’;
set global innodb_ft_aux_table=‘optimization/ft’;
5.查看索引信息
select * from information_schema.INNODB_FT_INDEX_CACHE;
6.测试,查询时条件值无论是什么会对查询条件进行拆词,按照匹配优先级进行匹配
explain select * from ft where MATCH(address) AGAINST(‘北京123市’);

4.组合索引(最左前缀)
组合索引是创建索引时至少有两个列添加索引。创建了组合索引时实际上是创建了多个索引。
所以在建立联合索引时把最常用的列放在最左边
show index from teacher;
create index mul_index on teacher(name,address);

使用索引,type=ref

explain select * from teacher where name=‘老师1’;

没有使用索引,type=index

explain select * from teacher where address=‘oracle is a database’;

使用索引,type=ref

explain select * from teacher where name = ‘老师1’ and address=‘o’;
4.1.创建索引
CREATE INDEX index_name ON table_name (column_list)
5.MySQL中的索引优化
上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点。虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE次数大于查询次数时,放弃索引。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。
5.1.使用短索引(前缀索引)
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
CREATE INDEX index_name ON table_name (column(length))
5.2.索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
5.3.like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引,而like “aaa%”(非前导模糊查询)可以使用索引。
使用后,优化到range级别
explain select * from teacher where address like ‘%oracle%’;

5.4.不要在列上进行运算
例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<’2007-01-01′。
应该把计算放在业务代码上完成,而不是交给数据库
5.5 范围列可以使用索引
范围条件有:<、<=、>、>=、between等。
范围列可以用到索引(联合索引必须是最左前缀),但是范围列后面的列无法用到索引,索引最多用于一个范围列,如果查询条件中有两个范围列则无法全用到索引。所以where中把最主要的查询条件放在第一个。
alter table teacher add column (age int(3));
alter table teacher add column (weight int(3));
select * from teacher;
update teacher set age=10,weight=90 where id = 1;
update teacher set age=20,weight=100 where id = 2;
update teacher set age=30,weight=110 where id = 3;

create index age_index on teacher(age);
create index weight_index on teacher(weight);

explain select * from teacher where age between 10 and 20 and weight between 90 and 100;
5.6 类型转换会导致索引无效
当列是文本类型时,把数值类型当作列的条件会弃用索引
explain select * from teacher where name = 20;

6.索引总结
最后总结一下,MySQL只对以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的。
建议:一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
7.MySQL中的SQL的常见优化策略
7.1.NULL值
在老版本中含有NULL的列无法触发索引,但是在MySQL 5.7 中已经可以触发索引了。但是可能出现“无法预料的结果”。
所以在建立表时给列添加not null 约束或default 默认值
7.2.避免全表扫描
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
7.3.避免负向条件
应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
负向条件有:!=、<>、not in、not exists、not like 等
explain select * from teacher where address !=‘aa’;
7.4.避免使用or逻辑
应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
在目前MySQL5.7 中or已经可以触发索引了,老版本不可以。
7.5.慎用in和not in逻辑
in可以代替union all操作,虽然对CPU性能稍微增加一些,但是也可以忽略不计了。
in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t1 where num in(select id from t2 where id > 10)
此时外层查询会全表扫描,不使用索引。可以修改为:
select id from t1,(select id from t1 where id > 10)t2 where t1.id = t2.id
此时索引被使用,可以明显提升查询效率。
7.6.注意模糊查询
下面的查询也将导致全表扫描:
select id from t where name like ‘%abc%’
模糊查询如果是必要条件时,可以使用select id from t where name like 'abc%'来实现模糊查询,此时索引将被使用。如果头匹配是必要逻辑,建议使用全文搜索引擎(Elastic search、Lucene、Solr等)。
7.7.避免查询条件中字段计算
应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=1002
7.8.避免查询条件中对字段进行函数操作
应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)=‘abc’–name以abc开头的id
应改为:
select id from t where name like ‘abc%’
7.9.WHERE子句“=”左边注意点
不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
7.10.组合索引使用
在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
7.11.不要定义无意义的查询
不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(…)
7.12.exists
很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
7.13.索引也可能失效
并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
7.14.表格字段类型选择
尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
尽可能的使用 varchar 代替 char ,因为首先可变长度字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
7.15.查询语法中的字段
任何地方都不要使用 select * from t ,用具体的字段列表代替“
”,不要返回用不到的任何字段。
7.16.索引无关优化
不使用*、尽量不使用union,union all等关键字、尽量不使用or关键字、尽量使用等值判断。

表连接建议不超过5个。如果超过5个,则考虑表格的设计。(互联网应用中)

表连接方式使用外联优于内联。
外连接有基础数据存在。如:A left join B,基础数据是A。
A inner join B,没有基础数据的,先使用笛卡尔积完成全连接,在根据连接条件得到内连接结果集。

大数据量级的表格做分页查询时,如果页码数量过大,则使用子查询配合完成分页逻辑。
Select * from table limit 1000000, 10
Select * from table where id in (select pk from table limit 100000, 10)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值