DRDS分布式SQL引擎—执行计划介绍
摘要: 本文着重介绍 DRDS 执行计划中各个操作符的含义,以便用户通过查询计划了解 SQL 执行流程,从而有针对性的调优 SQL。
DRDS分布式SQL引擎 — 执行计划介绍
前言
数据库系统中,执行计划是对 SQL 如何执行的形式化表示,往往由若干关系操作符构成,用户可以通过对应的 EXPLAIN 命令查看,并通过执行计划大致了解 SQL 的执行过程和执行方式,如全表扫描还是索引扫描,归并连接还是哈希连接等。执行计划可以为用户进行 SQL 调优提供重要依据。
DRDS 执行计划
与多数数据库系统类似,DRDS 在处理 SQL 时,会通过优化器生成执行计划,该执行计划由关系操作符构成一个树形结构,反映 DRDS 如何执行 SQL 语句;不同的是,DRDS 本身不存储数据,更侧重考虑分布式环境中的网络 IO 开销,将运算下推到各个分库(如 RDS/MySQL)执行,从而提升 SQL 执行效率。用户可通过 EXPLAIN 命令查看 SQL 的执行计划。
本文着重介绍 DRDS 执行计划中各个操作符的含义,以便用户通过查询计划了解 SQL 执行流程,从而有针对性的调优 SQL。文中示例均基于如下表结构:
CREATE TABLE `sbtest1` (`id` INT(10) UNSIGNED NOT NULL,`k` INT(10) UNSIGNED NOT NULL DEFAULT '0',`c` CHAR(120) NOT NULL DEFAULT '',`pad` CHAR(60) NOT NULL DEFAULT '',KEY `xid` (`id`),KEY `k_1` (`k`)) dbpartition BY HASH (`id`) tbpartition BY HASH (`id`) tbpartitions 4
先通过一个例子整体了解 DRDS 执行计划的树形结构。
mysql> explain select a.k, count(*) cnt from sbtest1 a, sbtest1 b where a.id = b.k and a.id > 1000 group by k having cnt > 1300 order by cnt limit 5, 10;+---------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+---------------------------------------------------------------------------------------------------------------------------------------------------+| TmpSort(sort="cnt ASC", offset=?2, fetch=?3) || Filter(condition="cnt > ?1") || Aggregate(group="k", cnt="COUNT()") || BKAJoin(id="id", k="k", c="c", pad="pad", id0="id0", k0="k0", c0="c0", pad0="pad0", condition="id = k", type="inner") || MergeSort(sort="k ASC") || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?) ORDER BY `k`") || UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE ((`k` > ?) AND (`k` IN ('?')))") || HitCache:false |+---------------------------------------------------------------------------------------------------------------------------------------------------+9 rows in set (0.01 sec)
如上,DRDS EXPLAIN 的结果总体分为两部分:执行计划和其他信息。
执行计划
执行计划以缩进形式表示操作符之间的 "父-子" 关系。示例中,Filter 是 TmpSort 的子操作符,同时是 Aggregate 的父操作符。从真正执行的角度看,每个操作符均从其子操作符中获取数据,经当前操作符处理,输出给其父操作符。为方便理解,将以上执行计划转换为更加直观的树形结构:
其他信息
除执行计划外,EXPLAIN 结果中还会有一些额外信息,目前仅有一项 `HitCache` 。需要说明的是,DRDS 会默认开启 PlanCache 功能,`HitCache` 表示当前 SQL 是否命中 PlanCache。
开启 PlanCache 后,DRDS 会对 SQL 做参数化处理,参数化会将 SQL 中的大部分常量用
?替换,并构建一个参数列表。在执行计划中的体现就是,LogicalView 的sql中会有?,在部分操作符中会有类似?2的字样,这里的2表示其在参数列表中的下标,后续会结合具体的例子进一步阐述。
EXPLAIN 语法
EXPLAIN 用于查看 SQL 语句的执行计划,语法如下:
EXPLAIN explainable_stmtexplainable_stmt: {SELECT statement| DELETE statement| INSERT statement| REPLACE statement| UPDATE statement}
操作符介绍
本小节详细介绍 DRDS 执行计划中各个操作符的含义。
LogicalView
LogicalView 是从底层数据源获取数据的操作符。从数据库的角度来看,使用 TableScan 命名更符合常规,但考虑到 DRDS 本身不存储数据,而是通过 SQL 从底层数据源获取,因此,该操作符中会记录下推的 SQL 语句和数据源信息,这更像一个 "视图"。该 "视图" 中的 SQL,通过优化器的下推,可能包含多种操作,如投影、过滤、聚合、排序、连接和子查询等。
以下通过示例说明 EXPLAIN 中 LogicalView 的输出信息及其含义:
mysql> explain select * From sbtest1 where id > 1000;+-----------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-----------------------------------------------------------------------------------------------------------------------+| UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") || HitCache:false |+-----------------------------------------------------------------------------------------------------------------------+3 rows in set (0.00 sec)
LogicalView 的信息由三部分构成:
tables:底层数据源对应的表名,以
.分割,其前是分库对应的编号,其后是表名及其编号,对于连续的编号,会做简写,如[000-127],表示表名编号从000到127的所有表。shardCount:需要访问的分表总数,该示例中会访问从
000到127共 128 张分表。sql:下发至底层数据源的 SQL 模版。这里显示的并非真正下发的 SQL 语句,DRDS 在执行时会将表名替换为物理表名;另外,SQL 中的常量
10被?替换,这是因为 DRDS 默认开启了 PlanCache 功能,对 SQL 做了参数化处理。
UnionAll
UnionAll 是 UNION ALL 对应的操作符,该操作符通常有多个输入,表示将多个输入的数据 UNION 在一起。以上示例中,LogicalView 之上的 UnionAll 表示将所有分表中的数据进行 UNION。
UnionAll 中的 concurrent 表示是否并行执行其子操作符,默认为 true。
UnionDistinct
与 UnionAll 类似,UnionDistinct 是 UNION DISTINCT 对应的操作符。如下:
mysql> explain select * From sbtest1 where id > 1000 union distinct select * From sbtest1 where id < 200;+-------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-------------------------------------------------------------------------------------------------------------------------+| UnionDistinct(concurrent=true) || UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") || UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` < ?)") || HitCache:false |+-------------------------------------------------------------------------------------------------------------------------+6 rows in set (0.02 sec)
MergeSort
MergeSort,归并排序操作符,通常有多个子操作符。DRDS 中实现了两种排序:基于有序数据的归并排序和对无序数据的内存排序。如下:
mysql> explain select *from sbtest1 where id > 1000 order by id limit 5,10;+---------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+---------------------------------------------------------------------------------------------------------------------------------------------------+| MergeSort(sort="id ASC", offset=?1, fetch=?2) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?) ORDER BY `id` LIMIT (? + ?)") || HitCache:false |+---------------------------------------------------------------------------------------------------------------------------------------------------+3 rows in set (0.00 sec)
MergeSort 操作符包含三部分内容:
sort:表示排序字段以及排列顺序,
id ASC表示按照id字段递增排序,DESC表示递减排序。offset:表示获取结果集时的偏移量,同样由于对 SQL 做了参数化,示例中的
offst表示为?1,其中?表示这是一个动态参数,其后的数字对应参数列表的下标。示例中 SQL 对应的参数为[1000, 5, 10],因此,?1实际对应的值为5。fetch:表示最多返回的数据行数。与
offset类似,同样是参数化的表示,实际对应的值为10。
Aggregate
Aggregate 是聚合操作符,通常包含两部分内容:Group By 字段和聚合函数。如下:
mysql> explain select k, count(*) from sbtest1 where id > 1000 group by k;+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Aggregate(group="k", count(*)="SUM(count(*))") || MergeSort(sort="k ASC") || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, COUNT(*) AS `count(*)` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`") || HitCache:true |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+4 rows in set (0.00 sec)
Aggregate 包含两部分内容:
group:表示 GROUP BY 字段,示例中为
k。聚合函数:
=前为聚合函数对应的输出列名,其后为对应的计算方法。示例中count(*)="SUM(count(*))",第一个count(*)对应输出的列名,随后的SUM(count(*))表示对其输入数据中的count(*)列进行SUM运算得到最终的count(*)。
由此可见,DRDS 将聚合操作分为两部分,首先将聚合操作下推至底层数据源做局部聚合,最终在 DRDS 层面对局部聚合的结果做全局聚合。另外,DRDS 的最终聚合是基于排序做的,因此,会在优化器阶段为其添加一个 Sort 子操作符,而 Sort 操作符又进一步通过下推 Sort 转换为 MergeSort。
再来看一个 AVG 聚合函数的例子,如下:
mysql> explain select k, avg(id) avg_id from sbtest1 where id > 1000 group by k;+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN|+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Project(k="k", avg_id="sum_pushed_sum / sum_pushed_count")|| Aggregate(group="k", sum_pushed_sum="SUM(pushed_sum)", sum_pushed_count="SUM(pushed_count)")|| MergeSort(sort="k ASC")|| LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, SUM(`id`) AS `pushed_sum`, COUNT(`id`) AS `pushed_count` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`")|| HitCache:false|+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+5 rows in set (0.01 sec)
DRDS 会将 AVG 聚合函数转换为 SUM / COUNT,再分别根据 SUM 和 COUNT 的下推规则,将其转换为局部聚合和全局聚合。用户可自行尝试了解其他聚合函数的执行计划。
注意:DRDS 会将 DISTINCT 操作转换为 GROUP 操作,如下:
mysql> explain select distinct k from sbtest1 where id > 1000;+-----------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-----------------------------------------------------------------------------------------------------------------------------------------------------+| Aggregate(group="k") || MergeSort(sort="k ASC") || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`") || HitCache:false |+-----------------------------------------------------------------------------------------------------------------------------------------------------+4 rows in set (0.02 sec)
TmpSort
TmpSort,表示在内存中对数据进行排序。与 MergeSort 的区别在于,MergeSort 可以有多个子操作符,且每个子操作符返回的数据都已经排序。TmpSort 仅有一个子操作符。
TmpSort 对应的查询计划信息与 MergeSort 一致,请参考 MergeSort。
Project
Project 表示投影操作,即从输入数据中选择部分列输出,或者对某些列进行转换(通过函数或者表达式计算)后输出,当然,也可以包含常量。以上 AVG 的示例中,最顶层就是一个 Project,其输出 k 和 sum_pushed_sum / sum_pushed_count ,后者对应的列名为 avg_id 。
mysql> explain select '你好, DRDS', 1 / 2, CURTIME();+-------------------------------------------------------------------------------------+| LOGICAL PLAN |+-------------------------------------------------------------------------------------+| Project(你好, DRDS="_UTF-16'你好, DRDS'", 1 / 2="1 / 2", CURTIME()="CURTIME()") || || HitCache:false |+-------------------------------------------------------------------------------------+3 rows in set (0.00 sec)
可见,Project 的计划中包括每列的列名及其对应的列、值、函数或者表达式。
Filter
Filter 表示过滤操作,其中包含一些过滤条件。该操作符对输入数据进行过滤,若满足条件,则输出,否则丢弃。如下是一个较复杂的例子,包含了以上介绍的大部分操作符。
mysql> explain select k, avg(id) avg_id from sbtest1 where id > 1000 group by k having avg_id > 1300;+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Filter(condition="avg_id > ?1") || Project(k="k", avg_id="sum_pushed_sum / sum_pushed_count") || Aggregate(group="k", sum_pushed_sum="SUM(pushed_sum)", sum_pushed_count="SUM(pushed_count)") || MergeSort(sort="k ASC") || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k`, SUM(`id`) AS `pushed_sum`, COUNT(`id`) AS `pushed_count` FROM `sbtest1` WHERE (`id` > ?) GROUP BY `k` ORDER BY `k`") || HitCache:false |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+6 rows in set (0.01 sec)
在以上 AVG 示例的 SQL 基础上添加了having avg_id > 1300 ,执行计划最上层添加了一个 Filter 操作符,用于过滤所有满足 avg_id > 1300 的数据。
有读者可能会问,WHERE 中的条件为什么没有对应的 Filter 操作符呢?在 DRDS 优化器的某个阶段,WHERE 条件的 Filter 操作符的确是存在的,只是最终将其下推到了 LogiacalView 中,因此可以在 LogicalView 的 sql 中看到 id > 1000 。
NlJoin
NlJoin,表示 NestLoop Join 操作符,即使用 NestLoop 方法进行两表 Join。DRDS 中实现了两种 JOIN 策略:NlJoin 和 BKAJoin,后者表示 Batched Key Access Join,批量键值查询,会从左表取一批数据,构建一个 IN 条件拼接在访问右表的 SQL 中,从右表一次获取一批数据。
mysql> explain select a.* from sbtest1 a, sbtest1 b where a.id = b.k and a.id > 1000;+----------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+----------------------------------------------------------------------------------------------------------------------------+| Project(id="id", k="k", c="c", pad="pad") || NlJoin(id="id", k="k", c="c", pad="pad", k0="k0", condition="id = k", type="inner") || UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") || UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT `k` FROM `sbtest1` WHERE (`k` > ?)") || HitCache:false |+----------------------------------------------------------------------------------------------------------------------------+7 rows in set (0.03 sec)
NlJOIN 的计划包括三部分内容:
输出列信息:输出的列名,示例中的 JOIN 会输出 5 列
id="id", k="k", c="c", pad="pad", k0="k0"。contition:连接条件,示例中连接条件为
id = k。type:连接类型,示例中是 INNER JOIN,因此其连接类型为
inner。
BKAJoin
BKAJoin,Batched Key Access Join,表示通过批量键值查询的方式进行 JOIN,即从左表取一批数据,构建一个 IN 条件拼接在访问右表的 SQL 中,从右表一次获取一批数据进行 JOIN。
mysql> explain select a.* from sbtest1 a, sbtest1 b where a.id = b.k order by a.id;+-------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-------------------------------------------------------------------------------------------------------------------------------+| Project(id="id", k="k", c="c", pad="pad") || BKAJoin(id="id", k="k", c="c", pad="pad", id0="id0", k0="k0", c0="c0", pad0="pad0", condition="id = k", type="inner") || MergeSort(sort="id ASC") || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` ORDER BY `id`") || UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`k` IN ('?'))") || HitCache:false |+-------------------------------------------------------------------------------------------------------------------------------+7 rows in set (0.01 sec)
BKAJoin 的计划内容与 NlJoin 相同,这两个操作符命名不同,旨在告知执行器以何种方法执行 JOIN 操作。另外,以上执行计划中右表的 LogicalView 中 k IN ('?') 是优化器构建出来的对右表的IN查询模板。
LogicalModifyView
如上文介绍,LogicalView 表示从底层数据源获取数据的操作符,与之对应的,LogicalModifyView 表示对底层数据源的修改操作符,其中也会记录一个 SQL 语句,该 SQL 可能是 INSERT、UPDATE 或者 DELETE。
mysql> explain update sbtest1 set c='Hello, DRDS' where id > 1000;+--------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+--------------------------------------------------------------------------------------------------------------------------------+| LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="UPDATE `sbtest1` SET `c` = ? WHERE (`id` > ?)") || HitCache:false |+--------------------------------------------------------------------------------------------------------------------------------+2 rows in set (0.03 sec)mysql> explain delete from sbtest1 where id > 1000;+-------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-------------------------------------------------------------------------------------------------------------------------+| LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="DELETE FROM `sbtest1` WHERE (`id` > ?)") || HitCache:false |+-------------------------------------------------------------------------------------------------------------------------+2 rows in set (0.03 sec)
LogicalModifyView 查询计划的内容与 LogicalView 类似,包括下发的物理分表,分表数以及 SQL 模版。同样,由于开启了 PlanCache,对 SQL 做了参数化处理,SQL 模版中的常量会用 ? 替换。
PhyTableOperation
PhyTableOperation 表示对某个物理分表执行一个操作。该操作符目前仅用于 INSERT INTO ... VALUES ...。
mysql> explain insert into sbtest1 values(1, 1, '1', '1'),(2, 2, '2', '2');+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_001]", sql="INSERT INTO ? (`id`, `k`, `c`, `pad`) VALUES(?, ?, ?, ?)", params="`sbtest1_001`,1,1,1,1") || PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_002]", sql="INSERT INTO ? (`id`, `k`, `c`, `pad`) VALUES(?, ?, ?, ?)", params="`sbtest1_002`,2,2,2,2") || || HitCache:false |+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+4 rows in set (0.00 sec)
示例中,INSERT 插入两行数据,每行数据对应一个 PhyTableOperation 操作符,PhyTableOperation 操作符的内容包括三部分:
tables:物理表名,仅有唯一一个物理表名。
sql:SQL 模版,该 SQL 模版中表名和常量均被参数化,用
?替换,对应的参数在随后的 params 中给出。params:SQL 模版对应的参数,包括表名和常量。
其他信息
HitCache
DRDS 会默认开启 PlanCache 功能,HitCache 用于告知用户当前查询是否命中 PlanCache。如下,第一次运行 HitCache 为 false,第二次运行为 true。
mysql> explain select * From sbtest1 where id > 1000;+-----------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-----------------------------------------------------------------------------------------------------------------------+| UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") || HitCache:false |+-----------------------------------------------------------------------------------------------------------------------+3 rows in set (0.01 sec)mysql> explain select * From sbtest1 where id > 1000;+-----------------------------------------------------------------------------------------------------------------------+| LOGICAL PLAN |+-----------------------------------------------------------------------------------------------------------------------+| UnionAll(concurrent=true) || LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)") || HitCache:true |+-----------------------------------------------------------------------------------------------------------------------+3 rows in set (0.00 sec)
小结
以上介绍了 DRDS 5.3 的 EXPLAIN 命令,以及执行计划中每个操作符的含义,相信可以为用户调优 SQL 提供极大得便利。
DRDS 5.3 已经在阿里云正式上线,除全新设计的执行计划外,性能也有大幅提升,并支持原生事务、Outline 和 Plan Cache 等功能。后续支持复杂查询的只读实例、回收站、基于事务的广播表写入等功能也将相继上线,敬请期待。
DRDS分布式SQL引擎—执行计划介绍的更多相关文章
- 第三代DRDS分布式SQL引擎全新发布
DRDS (阿里云分布式关系型数据库服务,https://www.aliyun.com/product/drds)于 4 月 30 号发布了 5.3 版本,这是一个年度大更新.主要带来了以下特性: 性 ...
- sql server 执行计划(execution plan)介绍
大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习. 什么是 ...
- SQL Server 执行计划缓存
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...
- SQL Server 执行计划操作符详解(3)——计算标量(Compute Scalar)
接上文:SQL Server 执行计划操作符详解(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介绍第 ...
- SQL Server 执行计划操作符详解(2)——串联(Concatenation )
本文接上文:SQL Server 执行计划操作符详解(1)--断言(Assert) 前言: 根据计划,本文开始讲述另外一个操作符串联(Concatenation),读者可以根据这个词(中英文均可)先幻 ...
- db2执行计划介绍
在数据库调优过程中,SQL语句往往是导致性能问题的主要原因,而执行计划则是解释SQL语句执行过程的语言,只有充分读懂执行计划才能在数据库性能优化中做到游刃有余. 常见的关系型数据库中,虽然执行计划的表 ...
- Execution Plan 执行计划介绍
后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载. 下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 ...
- Oracle之SQL优化专题03-如何看懂SQL的执行计划
专题第一篇<Oracle之SQL优化专题01-查看SQL执行计划的方法>讲到了查看SQL执行计划的方法,并介绍了各种方法的应用场景,那么这一篇就主要介绍下如何看懂SQL的执行计划.毕竟如果 ...
- ORACLE从共享池删除指定SQL的执行计划
Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷新特定对象,例如游标,包,序列,触发器等.也就是说可以删除.清理特定SQL的执行计划 ...
随机推荐
- 安卓开发笔记(三十一):shape标签下子类根结点的具体使用
在我的上一篇博文当中阐述了我们如何使用shape标签进行自定义控件,这里对shape控件的属性进行阐述,不知道如何使用这些属性的可以参见我的上一篇博文(自定义Button):https://www.c ...
- 迎元旦,庆surging 1.0发布
一位摄影程序员的独白 每个人都有爱好,都有释放压力的活动,而我也不例外,我除了每天上班,周末就会约一群好友去拍妹子,成家后,就改为拍虫子,一拍就到了30岁,到了30岁就感觉到了中年的压力,这时候停下手 ...
- 带着新人看java虚拟机07(多线程篇)
这一篇说一下比较枯燥的东西,为什么说枯燥呢,因为我写这都感觉很无聊,无非就是几个阻塞线程的方法和唤醒线程的方法... 1.线程中断 首先我们说一说怎么使得一个正在运行中的线程进入阻塞状态,这也叫做线程 ...
- hive新建分区表
hive新建分区表语句如下: create table table_name (col1_name string comment '备注1', col2_name string comment '备注 ...
- Hadoop HA高可用集群搭建(Hadoop+Zookeeper+HBase)
声明:作者原创,转载注明出处. 作者:帅气陈吃苹果 一.服务器环境 主机名 IP 用户名 密码 安装目录 master188 192.168.29.188 hadoop hadoop /home/ha ...
- 重学前端 --- Promise里的代码为什么比setTimeout先执行?
首先通过一段代码进入讨论的主题 var r = new Promise(function(resolve, reject){ console.log("a"); resolve() ...
- 抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式概述 定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类 抽象工厂抽象工厂,顾名思义,就是比工厂模式更抽象的工厂模式.在工厂模式中,一个具体工厂只负责生产一个具体产品 ...
- 一份.NET 容器化的调查小结
小编在上个月在微信公众号"dotnet跨平台" 做了一个针对.NET 容器化的调查:https://mp.weixin.qq.com/s/oszbuIORT0G8XLLgMZzkn ...
- supervisord 备注
最近项目中使用了supervisord,简单做下备注. supervisord是linux下基于python开发的一个服务管理工具,类似之前node环境下的forever,用该方法启动进程后,supe ...
- 关于单元测试的思考--Asp.Net Core单元测试最佳实践
在我们码字过程中,单元测试是必不可少的.但在从业过程中,很多开发者却对单元测试望而却步.有些时候并不是不想写,而是常常会碰到下面这些问题,让开发者放下了码字的脚步: 这个类初始数据太麻烦,你看:new ...