1、优化SQL语句,使用Where限定查询的数据范围
2、建立相关字段的索引,避免查询时进行全表扫描
3、多数据表连接时,注意连接的主从表位置,避免小表Join大表
❷ SQL执行与优化
SQL优化
执行计划,表关联查询顺序,优化策略与思路
下面再向前走一些,容我根据自己的认识说一下查询执行的流程是怎样的:
1.连接
1.1客户端发起一条Query请求,监听客户端的‘连接管理模块’接收请求
1.2将请求转发到‘连接进/线程模块’
1.3调用‘用户模块’来进行授权检查
1.4通过检查后,‘连接进/线程模块’从‘线程连接池’中取出空闲的被缓存的连接线程和客户端请求对接,如果失败则创建一个新的连接请求
2.处理
2.1先查询缓存,检查Query语句是否完全匹配,接着再检查是否具有权限,都成功则直接取数据返回
2.2上一步有失败则转交给‘命令解析器’,经过词法分析,语法分析后生成解析树
2.3接下来是预处理阶段,处理解析器无法解决的语义,检查权限等,生成新的解析树
2.4再转交给对应的模块处理
2.5如果是SELECT查询还会经由‘查询优化器’做大量的优化,生成执行计划
2.6模块收到请求后,通过‘访问控制模块’检查所连接的用户是否有访问目标表和目标字段的权限
2.7有则调用‘表管理模块’,先是查看table cache中是否存在,有则直接对应的表和获取锁,否则重新打开表文件
2.8根据表的meta数据,获取表的存储引擎类型等信息,通过接口调用对应的存储引擎处理
2.9上述过程中产生数据变化的时候,若打开日志功能,则会记录到相应二进制日志文件中
3.结果
3.1Query请求完成后,将结果集返回给‘连接进/线程模块’
3.2返回的也可以是相应的状态标识,如成功或失败等
3.3‘连接进/线程模块’进行后续的清理工作,并继续等待请求或断开与客户端的连接
接下来再走一步,让我们看看一条SQL语句的前世今生。
首先看一下示例语句
示例语句
执行顺序
SQL解析
1. FROM
当涉及多个表的时候,左边表的输出会作为右边表的输入,之后会生成一个虚拟表VT1。
(1-J1)笛卡尔积
计算两个相关联表的笛卡尔积(CROSS JOIN) ,生成虚拟表VT1-J1。
两次全表扫描
哈希索引,查找复杂度都是 O(1) 。
2. WHERE
对VT1过程中生成的临时表进行过滤,满足WHERE子句的列被插入到VT2表中。
注意:
此时因为分组,不能使用聚合运算;也不能使用SELECT中创建的别名;
与ON的区别:
如果有外部列,ON针对过滤的是关联表,主表(保留表)会返回所有的列;
如果没有添加外部列,两者的效果是一样的;
应用:
对主表的过滤应该放在WHERE;
对于关联表,先条件查询后连接则用ON,先连接后条件查询则用WHERE;
hash join 哈希连接 驱动表和被驱动表都只会访问0次或1次
应用场景:一个大表一个小表/表上没有索引/返回结果集比较大
3. GROUP BY
这个子句会把VT2中生成的表按照GROUP BY中的列进行分组。生成VT3表。
注意:
其后处理过程的语句,如SELECT,HAVING,所用到的列必须包含在GROUP BY中,对于没有出现的,得用聚合函数;
原因:
GROUP BY改变了对表的引用,将其转换为新的引用方式,能够对其进行下一级逻辑操作的列会减少;
原作者的理解是:
根据分组字段,将具有相同分组字段的记录归并成一条记录,因为每一个分组只能返回一条记录,除非是被过滤掉了,而不在分组字段里面的字段可能会有多个值,多个值是无法放进一条记录的,所以必须通过聚合函数将这些具有多值的列转换成单值;
GROUP BY 重新聚合查询
4. HAVING
这个子句对VT3表中的不同的组进行过滤,只作用于分组后的数据,满足HAVING条件的子句被加入到VT4表中。
7.LIMIT
LIMIT子句从上一步得到的VT6虚拟表中选出从指定位置开始的指定行数据。
注意:
offset和rows的正负带来的影响;
当偏移量很大时效率是很低的,可以这么做:
采用子查询的方式优化,在子查询里先从索引获取到最大id,然后倒序排,再取N行结果集
采用INNER JOIN优化,JOIN子句里也优先从索引获取ID列表,然后直接关联查询获得最终结果
当前未用到索引,
三次full scan , table1 AS a / table2 AS b / GROUP BY
尽量少做重复的工作
控制同一语句的多次执/减少多次的数据转换/
杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销
关于临时表和表变量的选择
临时表产生使用SELECT INTO和CREATE TABLE + INSERT INTO的选择,一般情况下,SELECT INTO会比CREATE TABLE + INSERT INTO的方法快很多,但是SELECT INTO会锁定TEMPDB的系统表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用户并发环境下,容易阻塞其他进程,所以建议,在并发系统中,尽量使用CREATE TABLE + INSERT INTO,而大数据量的单个语句使用中,使用SELECT INTO。
子查询的用法
相关子查询可以用IN、NOT IN、EXISTS、NOT EXISTS引入
NOT IN、NOT EXISTS的相关子查询可以改用LEFT JOIN代替写法
如果保证子查询没有重复 ,IN、EXISTS的相关子查询可以用INNER JOIN 代替
IN``的相关子查询用EXISTS代替
不要用 COUNT (*)的子查询判断是否存在记录,最好用 LEFT` `JOIN 或者EXISTS,比如有人写这样的语句:
建立索引后,并不是每个查询都会使用索引,在使用索引的情况下,索引的使用效率也会有很大的差别。只要我们在查询语句中没有强制指定索引,
不要对索引字段进行运算,而要想办法做变换
不要对索引字段进行格式转换
不要对索引字段使用函数
不要对索引字段进行多字段连接
join关联查询的计算是很复杂的,特别是数据量比较大的情况下,实际情况还是拆解较快的
Join拆解的核心就是利用In关键字
要么用空间换时间,要么用时间换空间
多表连接的连接条件对索引的选择有着重要的意义,所以我们在写连接条件条件的时候需要特别注意。
A、多表连接的时候,连接条件必须写全,宁可重复,不要缺漏。
B、连接条件尽量使用聚集索引
C、注意ON、WHERE和HAVING部分条件的区别
ON是最先执行, WHERE次之,HAVING最后,因为ON是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,WHERE也应该比 HAVING快点的,因为它过滤数据后才进行SUM,在两个表联接时才用ON的,所以在一个表的时候,就剩下WHERE跟HAVING比较了
考虑联接优先顺序:
(1)INNER JOIN
(2)LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)
(3)CROSS JOIN
索引并不适用于所有情况:a.少量数据;b.频繁进行改动的字段,不适合做索引;c.很少使用的字段,不需要加索引
索引会提高数据查询效率,但是会降低“增、删、改”的效率。当不使用索引的时候,我们进行数据的增删改,只需要操作源表即可,但是当我们添加索引后,不仅需要修改源表,也需要再次修改索引,很麻烦。
先执行顺序, 是否走索引, 有无类型转换
18000 字的SQL优化大全
步步深入:MySQL架构总览->查询执行流程->SQL解析顺序
MySQL索引总结(4)——btree与hash区别
❸ sql优化的N种方法
1.SQL语句中IN包含的值不应过多:
例如:select id from t where num in(1,2,3) 对于连续的数值,能用between就不要用in了; 实测速度差距不是很大.
2.SELECT语句务必指明字段名称:
禁止用 * 来查询 ,禁止用 * 来查询 ,禁止用 * 来查询 , 查找哪个字段,就写具体的字段.
select * from user_test WHERE address=15988;
select address from user_test WHERE address=15988;
3.只查询一条数据的时候,使用limit 1
【这个很有用】
4.避免在where子句中对字段进行null值判断:
【实测:null值的判断依然走了索引】
explain select uid from user_test WHERE phone is null;
5.避免在where子句中对字段进行表达式操作:
6.对于联合索引来说,要遵守最左前缀法则:
例如组合索引(id,name,sex) 使用的时候,可以id 或者id,name . 禁止直接name,或者sex.会导致联合索引失败
注意: id, name,sex 这三个字段填写顺序不会有影响, mysql会自动优化成最左匹配的顺序.
前三条sql都能命中索引,中间两条由于不符合最左匹配原则,索引失效.
最后一条sql 由于有最左索引id 所以索引部分成功,部分失效. id字段索引使用成功.
7.尽量使用inner join,避免left join:
如果连接方式是inner join,在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表,但是left join在驱动表的选择上遵循的是左边驱动右边的原则,即left join左边的表名为驱动表。
【实测:不是很准确,具体用explain测试】
8.注意范围查询语句:
对于联合索引来说,如果存在范围查询,比如between、>、<等条件时,会造成后面的索引字段失效。
解决办法: 业务允许的情况下,使用 >= 或者<= 这样不影响索引的使用.
explain select * from user_test where uid=10 and name='张三' and phone='13527748096';
explain select * from user_test where uid between( 1 and 10) and name ='张三' and phone='13527748096';
9.不建议使用%前缀模糊查询:
例如 : LIKE“%name”或者LIKE“%name%”,这种查询会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。
explain select * from user_test where uid=10 and uid like "%1" ;
explain select * from user_test where uid=10 and uid like "1%" ;
10.在 where 子句中使用 or 来连接条件,如果or连接的条件有一方没有索引,将导致引擎放弃使用索引而进行全表扫描
解决办法: 将or连接的双方都建立索引,就可以使用.
explain select * from user_test where uid=10 or name='张三';
11.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。(此处存在疑点,我本人测试的时候,发现索引还是能使用到)
12.字符串类型的字段 查询的时候如果不加引号'' ,会导致自动进行隐式转换,然后索引失效
❹ 如何提高sql语句的执行效率
1、使用ordered提示
Oracle必须花费大量的时间来剖析多表的合并,用以确定表合并的最佳顺序。SQL表达式涉及七个乃至更多的表合并,那么有时就会需要超过30分钟的时间来剖析,Ordered这个提示(hint)和其他的提示一起使用能够产生合适的合并顺序。
2、使用ordered_predicates
ordered_predicates提示在查询的WHERE子句里指定的,并被用来指定布尔判断(Booleanpredicate)被评估的顺序。在没有ordered_predicates的情况下,Oracle会使用下面这些步骤来评估SQL判断的顺序:子查询的评估先于外层WHERE子句里的Boolean条件。
所有没有内置函数或者子查询的布尔条件都按照其在WHERE子句里相反的顺序进行评估,即最后一条判断最先被评估。每个判断都带有内置函数的布尔判断都依据其预计的评估值按递增排列。
3、限制表格合并评估的数量
提高SQL剖析性能的最后一种方法是强制取代Oracle的一个参数,这个参数控制着在评估一个查询的时候,基于消耗的优化器所评估的可能合并数量。
(4)如何优化sql查询扩展阅读:
1、表设计的优化,数据行的长度不要超过8020字节,如果超过这个长度的话在物理页中这条数据会占用两行从而造成存储碎片,降低查询效率。
2、语句的查询优化,保证在实现功能的基础上,尽量减少对数据库的访问次数;
3、建立高效的索引创建索引一般有以下两个目的:维护被索引列的唯一性和提供快速访问表中数据的策略。
大型数据库有两种索引即簇索引和非簇索引,一个没有簇索引的表是按堆结构存储数据,所有的数据均添加在表的尾部,而建立了簇索引的表,其数据在物理上会按照簇索引键的顺序存储。个表只允许有一个簇索引。
4、强制查询转换,有时候oracle 的优化器未必能走正确的查询路线,这个时候就需要添加一些hint 之类的来规定他的执行路线。当然了,这个未必是最好的处理方案。因为虽然现在走这个路线是对的,以为因为数据的变化到这这个HINT 变得不可取。
❺ SQL语句的几种优化方法
1、尽可能建立索引,包括条件列,连接列,外键列等。
2、尽可能让where中的列顺序与复合索引的列顺序一致。
3、尽可能不要select *,而只列出自己需要的字段列表。
4、尽可能减少子查询的层数。
5、尽可能在子查询中进行数据筛选 。
❻ 数据库牛人是如何进行SQL优化的
SQL 查询优化减少了查询所需的资源并提高了整体系统性能,在本文中,我们将讨论 SQL 查询优化、它是如何完成的、最佳实践及其重要性。
SQL 查询优化是编写高效的 SQL 查询,并在执行时间和数据库表示方面 提高查询性能 的迭代过程,查询优化是几个关系数据库管理系统 (RDBMS) 的一项重要功能。
查询是对来自数据库的数据或信息的问题或请求,需要编写一组数据库可以理解的预定义代码,结构化查询语言 (SQL) 和其他查询语言旨在检索或管理关系数据库中的数据。
数据库中的查询可以用许多不同的结构编写,并且可以通过不同的算法执行,写得不好的查询会消耗更多的系统资源,执行时间长,并可能导致服务损失,一个完美的查询可以减少执行时间并带来最佳的 SQL 性能。
SQL查询优化的主要目的是:
确保查询处于最佳路径和形式非常重要,SQL 查询过程需要最好的执行计划和计算资源,因为它们是 CPU 密集型操作,SQL 查询优化通过三个基本步骤完成:
解析确保查询在语法和语义上都是正确的,如果查询语法正确,则将其转换为表达式并传递到下一步。
优化在查询性能中扮演着重要的角色,并且可能很困难,任何考虑优化的查询执行计划都必须返回与之前相同的结果,但优化后的性能应该会有所提高。
SQL 查询优化包括以下基本任务:
最后,查询执行涉及将查询优化步骤生成的计划转化为操作,如果没有发生错误,此步骤将返回结果给用户。
一旦用户确定某个查询需要改进以优化 SQL 性能,他们就可以选择任何优化方法——优化 SQL 查询性能的方法有很多种,下面介绍了一些最佳实践。
提高查询性能的一种简单方法是将 SELECT * 替换为实际的列名,当开发人员在表中使用 SELECT * 语句时,它会读取每一列的可用数据。
使用 SELECT 字段名 FROM 而不是 SELECT * FROM 时,可以缩小查询期间从表中提取的数据的范围,这有助于提高查询速度。
循环中的 SQL 查询运行不止一次,这会显着降低运行速度,这些查询会不必要地消耗内存、CPU 能力和带宽,这会影响性能,尤其是当 SQL 服务器不在本地计算机上时,删除循环内的查询可提高整体查询性能。
使用SQL 服务器索引可以减少运行时间并更快地检索数据,可以使用聚集和非聚集 SQL 索引来优化 SQL 查询,非聚集索引单独存储,需要更多的磁盘空间,因此,了解何时使用索引很重要。
该OLAP功能“扩展了SQL解析函数的语法。” SQL 中的 OLAP 功能更快且易于使用,熟悉这些语法的 SQL 开发人员和 DBA 可以很容易地适应和使用它们。
OLAP 函数可以创建所有标准计算度量,例如排名、移动聚合、份额、期初至今、前期和未来期、平行期等。
查询优化器使用统计信息来确定如何最好地连接表、何时应该使用索引以及如何访问这些索引等,无论是手动还是自动,SQL 服务器统计信息都应该保持最新。
过时的 SQL Server 统计信息会影响表、索引或列统计信息,并导致查询计划性能不佳。
SQL 查询优化可以轻松提高系统性能,从而节省成本,优化 SQL 查询可以提高运营效率并加快性能,从而提高系统上线进度。
SQL 查询优化很重要,原因有很多,包括:
组织可以通过更快的响应时间获得可靠的数据访问和高水平的性能,优化 SQL 查询不仅可以提高整体系统性能,还可以提高组织的声誉,最终,SQL 查询优化的最佳实践帮助用户获得准确、快速的数据库结果。
❼ 一条sql执行过长的时间,你如何优化,从哪些方面
1、查看sql是否涉及多表的联表或者子查询,如果有,看是否能进行业务拆分,相关字段冗余或者合并成临时表(业务和算法的优化)
2、涉及链表的查询,是否能进行分表查询,单表查询之后的结果进行字段整合
3、如果以上两种都不能操作,非要链表查询,那么考虑对相对应的查询条件做索引。加快查询速度
4、针对数量大的表进行历史表分离(如交易流水表)
5、数据库主从分离,读写分离,降低读写针对同一表同时的压力,至于主从同步,mysql有自带的binlog实现 主从同步
6、explain分析sql语句,查看执行计划,分析索引是否用上,分析扫描行数等等
7、查看mysql执行日志,看看是否有其他方面的问题
个人理解:从根本上来说,查询慢是占用mysql内存比较多,那么可以从这方面去酌手考虑
❽ 怎样进行sql数据库的优化
1、数据库空间是个概述,在sqlserver里,使用语句 exec sp_spaceused 'TableName' 这个语句来查。
❾ 如何进行SQL性能优化
这里分享下mysql优化的几种方法。
1、首先在打开的软件中,需要分别为每一个表创建 InnoDB FILE的文件。