我们在工作中经常会听到这样的声音:“SQL查询慢?你给数据库加个索引啊”。虽然加索引并不一定能解决问题,但是这初步的体现了SQL优化的思想。 而数据库主要由三部分组成,分别是解析器、优化器和执行引擎。 ? 其执行逻辑是我们输入的SQL语句通过解析器解析成关系表达式,通过优化器把关系表达式转换成执行计划,最终通过执行引擎进行执行。 所以优化器在很大程度上决定了一个系统的性能。优化器的作用就好比找到两点之间的最短路径。 上篇文章我们提到了Calcite,Calcite本身就支持两种优化方式分别是RBO和CBO。 它是一种经验式的优化方法,优化规则都是预先定义好的,只需要将SQL按照优化规则的顺序往上套就行,一旦满足某个规则则进行优化。 随着大数据技术的飞速发展,静态的CBO已经无法满足我们SQL优化的需要了,静态的统计信息无法提供准确的参考,在执行计划的生成过程中动态统计才会得到最优的执行计划。 那么优化器的执行过程是怎样的呢?
背景 一般的,数据库管理系统(DBMS)有通用的架构模型,可分为四个模块:传输通信、查询处理器、执行引擎、存储引擎。其中查询处理器包括查询解析器和查询优化器,而查询优化器是实现SQL计划树优化的核心。 其中4分层搜索、5统一搜索模型,支持编写声明式规则进行查询优化,将搜索策略与数据模型分离,规则与算子分离,规则与搜索策略分离,实现优化器生成器。 1. 该模型适合优化复杂情况,内存占用较小,但优化质量无法保证,优化过程黑盒,不确定性/不可解释性较强。 4. 分层搜索 分为两阶段:查询重写 + 物理优化。 但优化规则较多时,搜索耗时较长或卡主。 总结 本文围绕SQL查询优化器进行展开说明,分别介绍优化器分类、优化器框架、优化器模型。 另,社区开源的SQL中间件Calcite具备完善的查询优化能力,基于Cascades统一搜索模型实现,更多可参考:《Calcite系列(九):执行流程-优化器优化》 推荐阅读 《数据库查询优化器的艺术》
在我们使用LINQ to SQL的时候,需要大量的使用OR设计器,虽然我们手工写代码也是完全可以实现的,但是OR设计器是非常强大的工具,我想有了它,没有几个人会去手工写代码,当然了,手动写代码也是必须的 ,这一篇我就写几个典型的需要手工写代码的情况 打开和关闭复数形式 默认情况下,OR设计器会将数据库对象从服务器资源管理器拖放到OR设计器上的时候,会自动将ies,s结尾修改为单数形式,这样可以更准确的表示实例化的实体类到单个数据记录的事实 扩展OR设计器生成的代码 的确,OR设计器为我们做了很多的东西,但是某些时候,我们还是不得不动动键盘,智能方便总有它的缺陷,比如下面这种情况: 比如我们查询数据库的Account表,而我们不需要它的密码列 ,和最后登陆时间列(假设表中是有这些列的),而在我们直接将一个表拖放到OR设计器中的时候,他模型是添加了这些列的,所以我们可能会使用如下的代码 var queryWithAlias = from u in
SparkSQLCatalyst优化器详解一、SparkSQLCatalyst导览宏观来看:SparkSQL语句,经过一个优化器(Catalyst),转化为RDD,交给集群执行。 称为未解析的逻辑计划(UnresolvedLogicalPlan,ULP)Analyzer模块:借助数据的元数据信息将ULP解析为逻辑计划(LogicalPlan,LP)Optimizer模块:根据各种RBO、CBO优化策略得到优化后的逻辑计划 (OptimizedLogicalPlan,OLP),主要是对LogicalPlan进行剪枝、合并等操作,进而删除掉一些无用计算,或对一些计算的多个步骤进行合并其中RBO是基于规则优化,CBO是基于代价优化 4.1RBO(基于规则的优化)RBO的优化策略就是对语法树再次进行一次遍历,模式匹配能够满足特定规则的节点,再进行相应的等价转换,即将一棵树等价地转换为另一棵树。 4.2CBO(基于代价的优化)CBO通过综合考虑数据的统计信息、操作算子的代价等因素,计算不同执行计划的代价,从而选择最优的物理执行计划,以提升查询性能。
概述 我们知道统计反馈(SFB)收集的SQL运行时的统计信息会保存在相应的共享游标中,但却不能够持久化,当数据库重启或者被优化的SQL文从内存中Age-out后,保存的信息就会丢失。 下一次执行时还要重新进行一遍自动重新优化。 虽然到目前为止,只有一种SQL计划指令就是动态采样指令(DYNAMIC_SAMPLING),用于指示优化器使用动态统计信息,但相信以后该功能会进一步得到强化。 另外,SQL计划指令(SQL Plan Directives)是基于查询表达式,而不是SQL语句,所以同一个SQL计划指令(SQL Plan Directives),可以被优化器应用多个SQL文中。 ※注意: 12c中SQL计划指令(SQL Plan Directives)只能通过12c自动重新优化(Automatic Reoptimization)功能 由优化器自己判断自动生成,无法通过手动生成。
嘉宾介绍: 在SQL优化中,除了可以通过修改参数的方式干预优化器工作外,还可以使用提示的方式进行干预,而且这种方式更加精准、不影响其他SQL,故使用场景更加广泛。 1. ALL_ROWS 说明: ALL_ROWS是针对整个目标SQL的Hint,它的含义是让优化器启用CBO,而且在得到目标SQL的执行计划时会选择那些吞吐量最佳的执行路径。 ALL_ROWS Hint其实就相当于对目标SQL启用CBO,其优化器为ALL_ROWS。从Oracle 10g开始,ALL_ROWS就是默认的优化器模式。 如果在目标SQL中除了ALL_ROWS之外还使用了其他与执行路径、表连接相关的Hint,则优化器会优先考虑ALL_ROWS。 4.测试案例 下面通过一个完整的案例,介绍混合使用各种不同的提示并观察其效果。
1、MySQL 查询优化器与 SQL 调试 (一)要想写出更好的 SQL,一些基础概念和 SQL 调试是必不可少的。下面我们来看下查询优化器给我们做了哪些优化,执行器真正执行的 SQL 语句是什么。 system user 的值是指服务器生成的非客户端线程,用于处理内部的任务。比如:延迟行处理程序线程或副本主机上使用的 I/O 或 SQL 线程。 1.4、查询优化器MySQL 使用基于成本的优化器,它将尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最小的一个。如何查询 SQL 的执行成本呢? 1.4.1、查询优化器做了哪些优化有以下部分优化内容:重新定义关联表顺序MySQL 会根据相关的嵌套循环算法找到扫描行数更少的表去重新定义关联顺序。 但是有时候优化器给出的不是最佳的关联顺序,如果有超过 n 个表的关联,优化器需要检查 n 的阶乘种关联顺序,当这个变得非常大的时候,优化器不可能去检查每一种的关联成本,这时候优化器会选择 “贪婪” 搜索的方式查找
ON: 对vt1表应用ON筛选器只有满足 join_condition 为真的行才被插入vt2 3. 4. WHERE:对vt3应用 WHERE 筛选器只有使 where_condition 为true的行才被插入vt4 5. 只要我们在查询语句中没有强制指定索引,索引的选择和使用方法是SQLSERVER的优化器自动作的选择,而它选择的根据是查询语句的条件以及相关表的统计信息,这就要求我们在写SQL语句的时候尽量使得优化器可以使用索引 为了使得优化器能高效使用索引,写语句的时候应该注意: (1)不要对索引字段进行运算,而要想办法做变换,比如: SELECT ID FROM T WHERE NUM/2=100 应改为: SELECT ID 我们可以用回滚来调试我们的存储过程或者是SQL语句,从而排错。
1.1.order by优化1.1.1.知识点回顾在讲解order by优化前,先回顾一下order by的语法知识。 asc , age desc;1.1.2.两种排序方式MySQL有两种排序方式Using filesort和Using index,Using index的性能高于Using filesort,我们在优化排序操作时 ,尽量要优化为 Using indexUsing filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 1.1.3.order by优化案例演示1.1.3.1.案例A在上面我们创建了字段age和phone的联合索引,而且没有指定索引的排序顺序,此时索引在表中默认是按照升序排列的。 :MySQL有两种排序方式Using filesort和Using index,在优化排序操作时,尽量要优化为 Using index根据排序字段建立合适的索引,多字段排序时,索引需要遵循最左前缀法则。
MySQL常见的优化手段分为下面几个方面: SQL优化、设计优化,硬件优化等,其中每个大的方向中又包含多个小的优化点 SQL优化 此优化方案指的是通过优化 SQL 语句以及索引来提高 MySQL 数据库的运行效率 ,如果在一个 SQL 中关联的表越多,所占用的内存也就越大 如果程序中大量的使用了多表关联的操作,同时join_buffer_size设置的也不合理的情况下,就容易造成服务器内存溢出的情况,就会影响到服务器数据库性能的稳定性 的各个子查询中,以便优化器可以充分利用这些条件进行优化 此外,除非确实需要服务器去重,一定要使用union all,如果不加all关键字,MySQL会给临时表加上distinct选项,这会导致对整个临时表做唯一性检查 ,代价很高 慢查询日志 出现慢查询通常的排查手段是先使用慢查询日志功能,查询出比较慢的 SQL 语句,然后再通过 Explain 来查询 SQL 语句的执行计划,最后分析并定位出问题的根源,再进行处理 在大多数场景下,这两种类型都能良好地工作,但是建议使用timestamp,因为datetime占用8个字节,timestamp只占用了4个字节,timestamp空间效率更高 BLOB和TEXT类型 blob
SQL 优化 负向查询不能使用索引 select name from user where id not in (1,3,4); 应该修改为: select name from user where id user where create_time < FROM_UNIXTIME(CURDATE()); 最左前缀问题 如果给 user 表中的 username pwd 字段创建了复合索引那么使用以下SQL
优化手段: ① SQL优化 避免 SELECT *,只查询需要的字段。 小表驱动大表,即小的数据集驱动大的数据集: 当B表的数据集比A表小时,用in优化 exist两表执行顺序是先查B表再查A表查询语句:SELECT * FROM tb_dept WHERE id in ( ② 优化索引的使用 尽量使用主键查询,而非其他索引,因为主键查询不会触发回表查询。 不做列运算,把计算都放入各个业务系统实现 查询语句尽可能简单,大语句拆小语句,减少锁时间 or 查询改写成 union 查询 不用函数和触发器 避免 %xx 查询,可以使用:select * from 尽可能使用 not null 定义字段,因为 null 占用 4 字节空间。数字可以默认 0 ,字符串默认 “” 尽量少用 text 类型,非用不可时最好独立出一张表。
1.有哪些数据库优化方面的经验? 用PreparedStatement, 一般来说比Statement性能高:一个sql 发给服务器去执行,涉及步骤:语法检查、语义分析, 编译,缓存。 4.mysql支持的复制类型? 基于语句的复制: 在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。 基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍.
SQL的编写尽量使用索引库查询。索引库查询是小表查询操作,耗费的查询数据性能时间较少。索引失效是由like模糊匹配所产生的查询性能问题。 SQL的编写过程涉及到的子查询不能嵌套太多,子查询会在运行内存中给数据输出对象分配内存空间。嵌套分配内存不利于内存空间的释放。表与表之间的关联关系建立通过外键和主表的主键进行关联。 SQL的数据输出数据区尽量使用简单的数据。聚集函数在SQL的输出数据区存在会生成数据输出集合,类似复杂数据对象不利于数据的检索。聚集函数输出数据会产生索引失效,需要重新对输出数据建立索引。 SQL的条件过滤is null 是不会扫描索引表。节省数据索引表的内存空间。条件or关键字尽量少用,也是不会和数据索引表产生关联。数据表的小表类似索引表,大表类似数据库记录表。
Mysql查询优化方法 重点 思路:便面全表扫描 禁止用* 来查询,需要指定字段 in的个数在1000个以内 查询一条数据使用limit 1 尽量使用inner join 避免使用left join ! = 用 > or < 替换 between代替in exist 代替in 例如:优化前10s,优化后5s SELECT * from product WHERE title IN (SELECT title 所谓双机热备其实是一个复制的过程,复制过程中一个服务器充当主服务器,一个或多个服务器充当从服务。 这个复制的过程实质上是从服务器复制主服务器上MySQL的二进制日志(bin-log),并在从服务器上还原主服务器上的操作。 db_test #日志文件操作的数据库(可选属性 ,默认所有数据库的相关操作都写入二进制日志文件) ,如果有多个数据库,可以重复配置这个属性 expire_logs_days=30 启动MySQL # 4.
start transaction; insert into tb test values(1,'Tom'),(2,'Cat'),(3,Jerry'); insert into tb test values(4, 开启从本地加载文件导入数据的开关 set global local_infile =1; #执行load指令将准备好的数据,加载到表结构中 load data local infile '/root/sql1 当页中删除的记录达到MERGE _THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。 优化思路:一般分页查询时,通过创建覆盖索引能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。 count() InoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加。
SQL书写习惯 SQL语句尽量使用大写。 Oracle解析SQL语句时,会把小写的字母转换成大写的再执行。 T_ID=T2.T_ID 表连接语句 AND T1.T=’Y’ 条件语句 从下至上的顺序 相同查询要保持SQL 只有第一列被WHERE子句引用时,优化器才会选择使用该索引。当仅引用索引的第二列时,优化器使用全表扫描而忽略了索引。
优化 原因:性能低、执行时间太长、等待时间太长、SQL语句欠佳(连接查询)、索引失效、服务器参数设置不合理(缓冲、线程数) a.SQL : 编写过程: select dinstinct ..from 性能问题 a.分析SQL的执行计划 : explain ,可以模拟SQL优化器执行SQL语句,从而让开发人员 知道自己编写的SQL状况 b.MySQL查询优化其会干扰我们的优化 优化方法,官网:https 4 ; --虽然编写的顺序 和索引顺序不一致,但是 sql在真正执行前 经过了SQL优化器的调整,结果与上条SQL是一致的。 =2 ; 体验概率情况(< > =):原因是服务层中有SQL优化器,可能会影响我们的优化。 and typeid =2 ;--复合索引全部失效 --我们学习索引优化 ,是一个大部分情况适用的结论,但由于SQL优化器等原因 该结论不是100%正确。
IS NULL 与 IS NOT NULL 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。 联接列 对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。 下面是一个采用联接查询的SQL语句,这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。 然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用: select * from employee where last_name like ‘c%'; 4. 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。
4. 尽量将数据的处理工作放在服务器上,减少网络的开销,如使用存储过程。存储过程是编译好、优化过、并且被组织到一个执行规划里、且存储在数据库中的SQL语句,是控制流语言的集合,速度当然快。 下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢: SELECT * FROM record WHERE substrINg(card_no,1,4)=’5378’ (13秒) SELECT 运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样: SELECT (例如:列出上个月的每一天,我会用connect by去递归查询一下,绝不会去用循环从上个月第一天到最后一天) 选择最有效率的表名顺序(只在基于规则的优化器中有效): oracle 的解析器按照从右到左的顺序处理