精华内容
下载资源
问答
  • 开发一条sql语句,insert .....select形式,单独执行select部分有结果,但insert。。。select的时候,显示插入结果为0,同样的数据,该语句放在10g,11gR1上都没问题,能够插入数据。只能说恭喜发财了。 语句如下: ...

    将原有的系统迁移到oracle 12c上面,版本是12.1.0.2,总是有各种问题出现,不得不说,目前的版本真是个坑。

    开发一条sql语句,insert .....select形式,单独执行select部分有结果,但insert。。。select的时候,显示插入结果为0,同样的数据,该语句放在10g,11gR1上都没问题,能够插入数据。只能说恭喜发财了。

    语句如下:

    insert all when nvl
      ((BM10060851_2), 0) <> 0 then into KPI.KPI_ORGAN
      (data_date, organ_code, curr_type, kpi_code, KPI_FREQ, KPI_VALUE)
    values
      (to_date('20150730', 'YYYYMMDD'),
       org_no,
       '00',
       'BM10060851',
       'Q',
       BM10060851_2)
      select --/*+optimizer_features_enable('11.2.0.3')*/
      org_no,
             '00',
             to_number((count(distinct case
                     when GL_TYPE = 'Q' then
                      ACCT_NO
                   END)),'9999999999999999999999.999999') BM10060851_2
        from CMDATA.C_S_ELEC_TX_ORG T
       where chan_type = 'P01'
         and tran_status = '0'
         and data_dt = to_date('20150630', 'YYYYMMDD')
       group by org_no, '00'


    -------------------------------------------------------------------------------------------------------------------------------------------

    采用optimizer_features_enable指定优化器版本,发现11.2.0.4的时候,也会出现该问题,但11.2.0.3及以下版本就可以正常插入了。

    对此表示很无奈,定然是oracle的bug,而且可以说是很严重的bug,如果这个问题不是在测试库上发现而是在生产上,想想都觉得无语。

    在itpub上看到过类似的问题,也是sql语句在12c上执行没有结果,在之前的版本就可以,那哥们还开了sr给oracle,我这边客户也和原厂联系了,不知道是不是也要开个sr。

    一般对于这种问题,其实改写下写法多多数是可以避免的,比如客户在调试的时候就将select部分的case那块给改写了,这条语句就有结果,或者将insert all后面那个when部分去掉,也是可以正常插入结果。。。。

    但开发人员多是不愿意更改语句的,涉及到大量的程序,而且这个问题确实存在比较大的隐患,说不好下次写出类似语句便中招了,还是寄希望于oracle能及时处理吧。

    当然,针对该语句而言,如果急着使用的话,我觉得将hint,将优化器版本降低点也是可以对付过去的。

    --------------------------------------------------------------------------------------------------------------------------------------------

    写这个案例呢,倒不是跟以往那样提供啥解决方案,而是想给自己一点关于解决问题的思考。

    比如一开始遇到这个问题的时候,我便没有想到通过改写语句来避免这个情况,而是执着于去metalink上查找类似的bug,结果一无所得,

    也体现出了我思维的僵硬一面,很多问题不一定都会有明确的解决措施,也不一定你都是第二个遇到这个问题的人,如果哪天你是第一个了,

    是不是该考虑下创造历史,也为后来者做点贡献,毕竟这些年都在受惠于网络,于他人。

    另一方面,知识也决定了思维,狭隘的知识面终究只会在那一亩二分地里面摸索,跳不出来,也就难以达到新的高度,多学习,也便能多遇未知,有未知方能去思索,探索,如此这般,才能让自己站在不同的高度去看过去的风景。也许曾经折磨自己死去活来的问题,再回首时,一览众山小。

    --------------------------------------------------------------------------------------------------------------------------------------------

    累了就休息,清闲了就看点书,遇到不解之处就多思考,学到东西就多总结,多分享。


    展开全文
  • SQL语句执行过程详解

    万次阅读 2017-04-15 09:30:58
    SQL语句执行过程详解 一条sql,plsql的执行到底是怎样执行的呢? 一、SQL语句执行原理: 第一步:客户端把语句发给服务器端执行 当我们在客户端执行 select 语句时,客户端会把这条 SQL 语句发送给服务器端,让...
    SQL语句执行过程详解
    一条sql,plsql的执行到底是怎样执行的呢?
    一、SQL语句执行原理:
    第一步:客户端把语句发给服务器端执行
    当我们在客户端执行 select 语句时,客户端会把这条 SQL 语句发送给服务器端,让服务器端的
    进程来处理这语句。也就是说,Oracle 客户端是不会做任何的操作,他的主要任务就是把客户端产生
    的一些 SQL 语句发送给服务器端。虽然在客户端也有一个数据库进程,但是,这个进程的作用跟服务器
    上的进程作用事不相同的。服务器上的数据库进程才会对SQL 语句进行相关的处理。不过,有个问题需
    要说明,就是客户端的进程跟服务器的进程是一一对应的。也就是说,在客户端连接上服务器后,在客户
    端与服务器端都会形成一个进程,客户端上的我们叫做客户端进程;而服务器上的我们叫做服务器进程。
    第二步:语句解析
    当客户端把 SQL 语句传送到服务器后,服务器进程会对该语句进行解析。同理,这个解析的工作,
    也是在服务器端所进行的。虽然这只是一个解析的动作,但是,其会做很多“小动作”。
    1. 查询高速缓存(library cache)。服务器进程在接到客户端传送过来的 SQL 语句时,不
    会直接去数据库查询。而是会先在数据库的高速缓存中去查找,是否存在相同语句的执行计划。如果在
    数据高速缓存中,则服务器进程就会直接执行这个 SQL 语句,省去后续的工作。所以,采用高速数据缓
    存的话,可以提高 SQL 语句的查询效率。一方面是从内存中读取数据要比从硬盘中的数据文件中读取
    数据效率要高,另一方面,也是因为这个语句解析的原因。
    不过这里要注意一点,这个数据缓存跟有些客户端软件的数据缓存是两码事。有些客户端软件为了
    提高查询效率,会在应用软件的客户端设置数据缓存。由于这些数据缓存的存在,可以提高客户端应用软
    件的查询效率。但是,若其他人在服务器进行了相关的修改,由于应用软件数据缓存的存在,导致修改的
    数据不能及时反映到客户端上。从这也可以看出,应用软件的数据缓存跟数据库服务器的高速数据缓存
    不是一码事。
    2. 语句合法性检查(data dict cache)。当在高速缓存中找不到对应的 SQL 语句时,则服
    务器进程就会开始检查这条语句的合法性。这里主要是对 SQL 语句的语法进行检查,看看其是否合乎
    语法规则。如果服务器进程认为这条 SQL 语句不符合语法规则的时候,就会把这个错误信息,反馈给客
    户端。在这个语法检查的过程中,不会对 SQL 语句中所包含的表名、列名等等进行 SQL 他只是语法
    上的检查。
    3. 语言含义检查(data dict cache)。若 SQL 语句符合语法上的定义的话,则服务器进程
    接下去会对语句中的字段、表等内容进行检查。看看这些字段、表是否在数据库中。如果表名与列名不
    准确的话,则数据库会就会反馈错误信息给客户端。所以,有时候我们写 select 语句的时候,若语法
    与表名或者列名同时写错的话,则系统是先提示说语法错误,等到语法完全正确后,再提示说列名或表名
    错误。
    4. 获得对象解析锁(control structer)。当语法、语义都正确后,系统就会对我们需要查询
    的对象加锁。这主要是为了保障数据的一致性,防止我们在查询的过程中,其他用户对这个对象的结构发
    生改变。
    5. 数据访问权限的核对(data dict cache)。当语法、语义通过检查之后,客户端还不一定
    能够取得数据。服务器进程还会检查,你所连接的用户是否有这个数据访问的权限。若你连接上服务器
    的用户不具有数据访问权限的话,则客户端就不能够取得这些数据。有时候我们查询数据的时候,辛辛苦
    苦地把 SQL 语句写好、编译通过,但是,最后系统返回个 “没有权限访问数据”的错误信息,让我们气
    半死。这在前端应用软件开发调试的过程中,可能会碰到。所以,要注意这个问题,数据库服务器进程先
    检查语法与语义,然后才会检查访问权限。
    6. 确定最佳执行计划 ?。当语句与语法都没有问题,权限也匹配的话,服务器进程还是不会直接对
    数据库文件进行查询。服务器进程会根据一定的规则,对这条语句进行优化。不过要注意,这个优化是有
    限的。一般在应用软件开发的过程中,需要对数据库的 sql 语言进行优化,这个优化的作用要大大地大
    于服务器进程的自我优化。所以,一般在应用软件开发的时候,数据库的优化是少不了的。当服务器进程
    的优化器确定这条查询语句的最佳执行计划后,就会将这条 SQL 语句与执行计划保存到数据高速缓存
    (library cache)。如此的话,等以后还有这个查询时,就会省略以上的语法、语义与权限检查的步骤,
    而直接执行 SQL 语句,提高 SQL 语句处理效率。
    第三步:语句执行
    语句解析只是对 SQL 语句的语法进行解析,以确保服务器能够知道这条语句到底表达的是什么意
    思。等到语句解析完成之后,数据库服务器进程才会真正的执行这条 SQL 语句。这个语句执行也分两
    种情况。
    一是若被选择行所在的数据块已经被读取到数据缓冲区的话,则服务器进程会直接把这个数据传递
    给客户端,而不是从数据库文件中去查询数据。
    若数据不在缓冲区中,则服务器进程将从数据库文件中查询相关数据,并把这些数据放入到数据缓冲
    区中(buffer cache)。
    第四步:提取数据
    当语句执行完成之后,查询到的数据还是在服务器进程中,还没有被传送到客户端的用户进程。所以,
    在服务器端的进程中,有一个专门负责数据提取的一段代码。他的作用就是把查询到的数据结果返回给
    用户端进程,从而完成整个查询动作。从这整个查询处理过程中,我们在数据库开发或者应用软件开发过
    程中,需要注意以下几点:
    一是要了解数据库缓存跟应用软件缓存是两码事情。数据库缓存只有在数据库服务器端才存在,在
    客户端是不存在的。只有如此,才能够保证数据库缓存中的内容跟数据库文件的内容一致。才能够根据
    相关的规则,防止数据脏读、错读的发生。而应用软件所涉及的数据缓存,由于跟数据库缓存不是一码事
    情,所以,应用软件的数据缓存虽然可以提高数据的查询效率,但是,却打破了数据一致性的要求,有时候
    会发生脏读、错读等情况的发生。所以,有时候,在应用软件上有专门一个功能,用来在必要的时候清除
    数据缓存。不过,这个数据缓存的清除,也只是清除本机上的数据缓存,或者说,只是清除这个应用程序
    的数据缓存,而不会清除数据库的数据缓存。
    二是绝大部分 SQL 语句都是按照这个处理过程处理的。我们 DBA 或者基于 Oracle 数据库的
    开发人员了解这些语句的处理过程,对于我们进行涉及到 SQL 语句的开发与调试,是非常有帮助的。有
    时候,掌握这些处理原则,可以减少我们排错的时间。特别要注意,数据库是把数据查询权限的审查放在
    语法语义的后面进行检查的。所以,有时会若光用数据库的权限控制原则,可能还不能满足应用软件权限
    控制的需要。此时,就需要应用软件的前台设置,实现权限管理的要求。而且,有时应用数据库的权限管
    理,也有点显得繁琐,会增加服务器处理的工作量。因此,对于记录、字段等的查询权限控制,大部分程
    序涉及人员喜欢在应用程序中实现,而不是在数据库上实现。
    DBCC DROPCLEANBUFFERS
    从缓冲池中删除所有清除缓冲区。
    DBCC FREEPROCCACHE
    从过程缓存中删除所有元素。
    DBCC FREESYSTEMCACHE
    从所有缓存中释放所有未使用的缓存条目
    SQL语句中的函数、关键字、排序等执行顺序:
    1. FROM 子句返回初始结果集。
    2. WHERE 子句排除不满足搜索条件的行。
    3. GROUP BY 子句将选定的行收集到 GROUP BY 子句中各个唯一值的组中。
    4. 选择列表中指定的聚合函数可以计算各组的汇总值。
    5. 此外,HAVING 子句排除不满足搜索条件的行。
    6. 计算所有的表达式;
    7. 使用 order by 对结果集进行排序。
    8. 查找你要搜索的字段。
    二、SQL语句执行完整过程:
    1.用户进程提交一个 sql 语句:
    update temp set a=a*2,给服务器进程。
    2.服务器进程从用户进程把信息接收到后,在 PGA 中就要此进程分配所需内存,存储相关的信息,如在会
    话内存存储相关的登录信息等。
    3.服务器进程把这个 sql 语句的字符转化为 ASCII 等效数字码,接着这个 ASCII 码被传递给一个
    HASH 函数,并返回一个 hash 值,然后服务器进程将到shared pool 中的 library cache 中去查找是否存在相
    同的 hash 值,如果存在,服务器进程将使用这条语句已高速缓存在 SHARED POOL 的library cache 中的已
    分析过的版本来执行。
    4.如果不存在,服务器进程将在 CGA 中,配合 UGA 内容对 sql,进行语法分析,首先检查语法的正确性,接
    着对语句中涉及的表,索引,视图等对象进行解析,并对照数据字典检查这些对象的名称以及相关结构,并根据
    ORACLE 选用的优化模式以及数据字典中是否存在相应对象的统计数据和是否使用了存储大纲来生成一个
    执行计划或从存储大纲中选用一个执行计划,然后再用数据字典核对此用户对相应对象的执行权限,最后生成
    一个编译代码。
    5.ORACLE 将这条 sql 语句的本身实际文本、HASH 值、编译代码、与此语名相关联的任何统计数据
    和该语句的执行计划缓存在 SHARED POOL 的 library cache中。服务器进程通过 SHARED POOL 锁存
    器(shared pool latch)来申请可以向哪些共享 PL/SQL 区中缓存这此内容,也就是说被SHARED POOL 锁存
    器锁定的 PL/SQL 区中的块不可被覆盖,因为这些块可能被其它进程所使用。
    6.在 SQL 分析阶段将用到 LIBRARY
     CACHE,从数据字典中核对表、视图等结构的时候,需要将数据
    字典从磁盘读入 LIBRARY
     CACHE,因此,在读入之前也要使用LIBRARY
     CACHE 锁存器(library cache
    pin,library cache lock)来申请用于缓存数据字典。 到现在为止,这个 sql 语句已经被编译成可执行的代码了,
    但还不知道要操作哪些数据,所以服务器进程还要为这个 sql 准备预处理数据。
    7.首先服务器进程要判断所需数据是否在 db buffer 存在,如果存在且可用,则直接获取该数据,同时根据
    LRU 算法增加其访问计数;如果 buffer 不存在所需数据,则要从数据文件上读取首先服务器进程将在表头部
    请求 TM 锁(保证此事务执行过程其他用户不能修改表的结构),如果成功加 TM 锁,再请求一些行级锁(TX
    锁),如果 TM、TX 锁都成功加锁,那么才开始从数据文件读数据,在读数据之前,要先为读取的文件准备好
    buffer 空间。服务器进程需要扫面 LRU list 寻找 free db buffer,扫描的过程中,服务器进程会把发现的所有
    已经被修改过的 db buffer 注册到 dirty list 中, 这些 dirty buffer 会通过 dbwr 的触发条件,随后会被写出到
    数据文件,找到了足够的空闲 buffer,就可以把请求的数据行所在的数据块放入到 db buffer 的空闲区域或者
    覆盖已经被挤出 LRU list 的非脏数据块缓冲区,并排列在 LRU list 的头部,也就是在数据块放入 DB
    BUFFER 之前也是要先申请 db buffer 中的锁存器,成功加锁后,才能读数据到 db buffer。
    8.记日志 现在数据已经被读入到 db buffer 了,现在服务器进程将该语句所影响的并被读
    入 db buffer 中的这些行数据的 rowid 及要更新的原值和新值及 scn 等信息从 PGA 逐条的写入 redo log
    buffer 中。在写入 redo log buffer 之前也要事先请求 redo log buffer 的锁存器,成功加锁后才开始写入,当
    写入达到 redo log buffer 大小的三分之一或写入量达到 1M 或超过三秒后或发生检查点时或者 dbwr 之前
    发生,都会触发 lgwr 进程把 redo log buffer 的数据写入磁盘上的 redo file 文件中(这个时候会产生log file
    sync 等待事件)
    已经被写入 redofile 的 redo log buffer 所持有的锁存器会被释放,并可被后来的写入信息覆盖,
    redo log buffer是循环使用的。Redo file 也是循环使用的,当一个 redo file 写满后,lgwr 进程会自动切换到
    下一 redo file(这个时候可能出现 log fileswitch(checkpoint complete)等待事件)。如果是归档模式,归档进
    程还要将前一个写满的 redo file 文件的内容写到归档日志文件中(这个时候可能出现 log file
    switch(archiving needed)。
    9.为事务建立回滚段 在完成本事务所有相关的 redo log buffer 之后,服务器进程开始改写这个 db buffer
    的块头部事务列表并写入 scn,然后 copy 包含这个块的头部事务列表及 scn 信息的数据副本放入回滚段中,将
    这时回滚段中的信息称为数据块的“前映像“,这个”前映像“用于以后的回滚、恢复和一致性读。(回滚段可以
    存储在专门的回滚表空间中,这个表空间由一个或多个物理文件组成,并专用于回滚表空间,回滚段也可在其它
    表空间中的数据文件中开辟。
    10.本事务修改数据块 准备工作都已经做好了,现在可以改写 db buffer 块的数据内容了,并在块的头部写
    入回滚段的地址。
    11.放入 dirty list 如果一个行数据多次 update 而未 commit,则在回滚段中将会有多个“前映像“,除了第
    一个”前映像“含有 scn 信息外,其他每个“前映像“的头部都有 scn 信息和“前前映像”回滚段地址。一个
    update 只对应一个 scn,然后服务器进程将在 dirty list 中建立一
    条指向此 db buffer 块的指针(方便 dbwr 进程可以找到 dirty list 的 db buffer 数据块并写入数据文件中)。
    接着服务器进程会从数据文件中继续读入第二个数据块,重复前一数据块的动作,数据块的读入、记日志、建
    立回滚段、修改数据块、放入 dirty list。当 dirty queue 的长度达到阀值(一般是 25%),服务器进程将通知
    dbwr 把脏数据写出,就是释放 db buffer 上的锁存器,腾出更多的 free db buffer。前面一直都是在说明
    oracle 一次读一个数据块,其实 oracle 可以一次读入多个数据块(db_file_multiblock_read_count 来设置一
    次读入块的个数)
    说明:
    在预处理的数据已经缓存在 db buffer 或刚刚被从数据文件读入到 db buffer 中,就要根据 sql 语句
    的类型来决定接下来如何操作。
    1>如果是 select 语句,则要查看 db buffer 块的头部是否有事务,如果有事务,则从回滚段中读取数据;如
    果没有事务,则比较 select 的 scn 和 db buffer 块头部的 scn,如果前者小于后者,仍然要从回滚段中读取数据;
    如果前者大于后者,说明这是一非脏缓存,可以直接读取这个 db buffer 块的中内容。
    2>如果是 DML 操作,则即使在 db buffer 中找到一个没有事务,而且 SCN 比自己小的非脏
    缓存数据块,服务器进程仍然要到表的头部对这条记录申请加锁,加锁成功才能进行后续动作,如果不成功,则要
    等待前面的进程解锁后才能进行动作(这个时候阻塞是 tx 锁阻塞)。
    用户 commit 或 rollback 到现在为止,数据已经在 db buffer 或数据文件中修改完
    成,但是否要永久写到数文件中,要由用户来决定 commit(保存更改到数据文件) rollback 撤销数据的更改)。
    1.用户执行 commit 命令
    只有当 sql 语句所影响的所有行所在的最后一个块被读入 db buffer 并且重做信息被写入 redo log
    buffer(仅指日志缓冲区,而不包括日志文件)之后,用户才可以发去 commit 命令,commit 触发 lgwr 进程,但不
    强制立即 dbwr来释放所有相应 db buffer 块的锁(也就是no-force-at-commit,即提交不强制写),也就是说有
    可能虽然已经 commit 了,但在随后的一段时间内 dbwr 还在写这条 sql 语句所涉及的数据块。表头部的行锁
    并不在 commit 之后立即释放,而是要等 dbwr 进程完成之后才释放,这就可能会出现一个用户请求另一用户
    已经 commit 的资源不成功的现象。
    A .从 Commit 和 dbwr 进程结束之间的时间很短,如果恰巧在 commit 之后,dbwr 未结束之前断电,因为
    commit 之后的数据已经属于数据文件的内容,但这部分文件没有完全写入到数据文件中。所以需要前滚。由
    于 commit 已经触发 lgwr,这些所有未来得及写入数据文件的更改会在实例重启后,由 smon 进程根据重做日
    志文件来前滚,完成之前 commit 未完成的工作(即把更改写入数据文件)。
    B.如果未 commit 就断电了,因为数据已经在 db buffer 更改了,没有 commit,说明这部分数据不属于数
    据文件,由于 dbwr 之前触发 lgwr 也就是只要数据更改,(肯定要先有 log) 所有 DBWR,在数据文件上的修改
    都会被先一步记入重做日志文件,实例重启后,SMON 进程再根据重做日志文件来回滚。
    其实 smon 的前滚回滚是根据检查点来完成的,当一个全部检查点发生的时候,首先让 LGWR 进程将
    redo log buffer 中的所有缓冲(包含未提交的重做信息)写入重做日志文件,然后让 dbwr 进程将 db buffer 已
    提交的缓冲写入数据文件(不强制写未提交的)。然后更新控制文件和数据文件头部的 SCN,表明当前数据库
    是一致的,在相邻的两个检查点之间有很多事务,有提交和未提交的。
    像前面的前滚回滚比较完整的说法是如下的说明:

    A.发生检查点之前断电,并且当时有一个未提交的改变正在进行,实例重启之后,SMON 进程将从上一个
    检查点开始核对这个检查点之后记录在重做日志文件中已提交的和未提交改变,因为
    dbwr 之前会触发 lgwr,所以 dbwr 对数据文件的修改一定会被先记录在重做日志文件中。因此,断电前被
    DBWN 写进数据文件的改变将通过重做日志文件中的记录进行还原,叫做回滚,
    B. 如果断电时有一个已提交,但 dbwr 动作还没有完全完成的改变存在,因为已经提交,提交会触发 lgwr
    进程,所以不管 dbwr 动作是否已完成,该语句将要影响的行及其产生的结果一定已经记录在重做日志文件中
    了,则实例重启后,SMON 进程根据重做日志文件进行前滚.
    实例失败后用于恢复的时间由两个检查点之间的间隔大小来决定,可以通个四个参数设置检查点执行的频
    率:

    Log_checkpoint_interval:
    决定两个检查点之间写入重做日志文件的系统物理块(redo blocks)
    的大小,默认值是 0,无限制。
    log_checkpoint_timeout:
     两 个 检 查 点 之 间 的 时 间 长 度(秒)默 认 值 1800s。
    fast_start_io_target:
    决定了用于恢复时需要处理的块的多少,默认值是 0,无限制。
    fast_start_mttr_target:
    直接决定了用于恢复的时间的长短,默认值是 0,无限制(SMON 进程执行的前滚
    和回滚与用户的回滚是不同的,SMON 是根据重做日志文件进行前滚或回滚,而用户的回滚一定是根据回滚段
    的内容进行回滚的。
    在这里要说一下回滚段存储的数据,假如是 delete 操作,则回滚段将会记录整个行的数据,假如是 update,
    则回滚段只记录被修改了的字段的变化前的数据(前映像),也就是没有被修改的字段是不会被记录的,假如是
    insert,则回滚段只记录插入记录的 rowid。 这样假如事务提交,那回滚段中简单标记该事务已经提交;假如是
    回退,则如果操作是 delete,回退的时候把回滚段中数据重新写回数据块,操作如果是 update,则把变化前数据
    修改回去,操作如果是 insert,则根据记录的 rowid 把该记录删除。
    2.如果用户 rollback。
    则服务器进程会根据数据文件块和 DB BUFFER 中块的头部的事务列表和 SCN 以及回滚段地址找到
    回滚段中相应的修改前的副本,并且用这些原值来还原当前数据文件中已修改但未提交的改变。如果有多个
    “前映像”,服务器进程会在一个“前映像”的头部找到“前前映像”的回滚段地址,一直找到同一事务下的最早的
    一个“前映像”为止。一旦发出了 COMMIT,用户就不能rollback,这使得 COMMIT 后 DBWR 进程还没有
    全部完成的后续动作得到了保障。到现在为例一个事务已经结束了。
    说明:
     TM 锁:
    符合 lock 机制的,用于保护对象的定义不被修改。 TX 锁:
    这个锁代表一个事务,是行
    级锁,用数据块头、数据记录头的一些字段表示,也是符合 lock 机制,有 resource structure、lock
    structure、enqueue 算法。
    展开全文
  • SQL语句执行顺序

    千次阅读 多人点赞 2018-03-01 14:19:30
    可以参考另一篇:sql逻辑执行顺序MySQL的语句执行顺序MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个...

    可以参考另一篇:sql逻辑执行顺序

    MySQL的语句执行顺序

    MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明的,但是只有最后一个虚拟的表才会被作为结果返回。如果没有在语句中指定某一个子句,那么将会跳过相应的步骤。

    下面我们来具体分析一下查询处理的每一个阶段

    1. FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
    2. ON: 对虚表VT1进行ON筛选,只有那些符合<join-condition>的行才会被记录在虚表VT2中。
    3. JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
    4. WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表VT4中。
    5. GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
    6. CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
    7. HAVING: 对虚拟表VT6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表VT7中。
    8. SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。
    9. DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
    10. ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.
    11. LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。

     

    SQL语句执行顺序

    查询语句中select from where group by having order by的执行顺序
     
    1.查询中用到的关键词主要包含六个,并且他们的顺序依次为 
    select--from--where--group by--having--order by 
     
    其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序 
    与sql语句的书写顺序并不是一样的,而是按照下面的顺序来执行 
    from--where--group by--having--select--order by, 
    from:需要从哪个数据表检索数据 
    where:过滤表中数据的条件 
    group by:如何将上面过滤出的数据分组 
    having:对上面已经分组的数据进行过滤的条件  
    select:查看结果集中的哪个列,或列的计算结果 
    order by :按照什么样的顺序来查看返回的数据 
     
    2.from后面的表关联,是自右向左解析的 
    而where条件的解析顺序是自下而上的。 
     
    也就是说,在写SQL文的时候,尽量把数据量大的表放在最右边来进行关联, 
    而把能筛选出大量数据的条件放在where语句的最下面。

     

    3.连接查询的执行顺序

    SQL语句中join连表时on和where后都可以跟条件,那么对查询结果集,执行顺序,效率是如何呢?
    通过查询资料发现:
    区别:
    on是对中间结果进行筛选,where是对最终结果筛选。
    执行顺序:
    先进行on的过滤, 而后才进行join。
    效率:
    如果是inner join, 放on和放where产生的结果一样, 但没说哪个效率速度更高? 如果有outer join (left or right), 就有区别了, 因为on生效在先, 已经提前过滤了一部分数据, 而where生效在后.

     
     
    SQL Select语句完整的执行顺序【从DBMS使用者角度】: 
      1、from子句组装来自不同数据源的数据; 
      2、where子句基于指定的条件对记录行进行筛选; 
      3、group by子句将数据划分为多个分组; 
      4、使用聚集函数进行计算; 
      5、使用having子句筛选分组; 
      6、计算所有的表达式; 
      7、使用order by对结果集进行排序。 

    SQL Select语句的执行步骤【从DBMS实现者角度,这个对我们用户意义不大】: 
      1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义。 
      2) 语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。 
      3)视图转换,将涉及视图的查询语句转换为相应的对基表查询语句。 
      4)表达式转换, 将复杂的 SQL 表达式转换为较简单的等效连接表达式。 
      5)选择优化器,不同的优化器一般产生不同的“执行计划” 
      6)选择连接方式, ORACLE 有三种连接方式,对多表连接 ORACLE 可选择适当的连接方式。 
      7)选择连接顺序, 对多表连接 ORACLE 选择哪一对表先连接,选择这两表中哪个表做为源数据表。 
      8)选择数据的搜索路径,根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。 
      9)运行“执行计划”。 
     
     
     

    了解下T-SQL对查询逻辑处理。

    T-SQL逻辑查询的各个阶段

    (5)SELECT DISTINCT TOP(<top_specification>) <select_list>                      

    (1)FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate> 

    (2)WHERE <where_predicate>

    (3)GROUP BY <group_by_specification>

    (4)HAVING <having_predicate>

    (6)ORDER BY <order_by_list>

    T-SQL在查询各个阶级分别干了什么

    (1)FROM 阶段

        FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种join),主要有以下几个步骤:

      a.求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(cross join),求笛卡儿积,生成虚拟表VT1-J1。

          b.ON筛选器。这个阶段对上个步骤生成的VT1-J1进行筛选,根据ON子句中出现的谓词进行筛选,让谓词取值为true的行通过了考验,插入到VT1-J2。

          c.添加外部行。如果指定了outer join,还需要将VT1-J2中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。

        经过以上步骤,FROM阶段就完成了。概括地讲,FROM阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了join,还有apply,pivot,unpivot)

    (2)WHERE阶段

         WHERE阶段是根据<where_predicate>中条件对VT1中的行进行筛选,让条件成立的行才会插入到VT2中。

    (3)GROUP BY阶段

          GROUP阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个分组只有一行。

    (4)HAVING阶段

          该阶段根据HAVING子句中出现的谓词对VT3的分组进行筛选,并将符合条件的组插入到VT4中。

    (5)SELECT阶段

      这个阶段是投影的过程,处理SELECT子句提到的元素,产生VT5。这个步骤一般按下列顺序进行

            a.计算SELECT列表中的表达式,生成VT5-1。

            b.若有DISTINCT,则删除VT5-1中的重复行,生成VT5-2

            c.若有TOP,则根据ORDER BY子句定义的逻辑顺序,从VT5-2中选择签名指定数量或者百分比的行,生成VT5-3

    (6)ORDER BY阶段

         根据ORDER BY子句中指定的列明列表,对VT5-3中的行,进行排序,生成游标VC6. 

    One example for the inner join and where condition 

    select coulumns from table_01 inner join table_02 on 01.col1=02.col2 where 01 = 'A' and 02='B' with ur ;

    from the db2 plan it will Optimized Statement like below  which remove the join on condition and using where replace it :

     

    select coulumns from table_01 , table_02  where 01 = 'A' and 02='B'  and 01.col1=02.col2 with ur ;

     

    上面优化后的sql 未必是最佳的 ,有可能程序index 会用不到的 。

    ================华丽分割线 ==============

     

    详细说明

    from 子句--执行顺序为从后往前、从右到左

    表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后)

    oracle 的解析器按照从右到左的顺序处理,FROM 子句中的表名,FROM 子句中写在最后的表(基础表 driving table)将被最先处理,即最后的表为驱动表,在FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3 个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指被其他表所引用的表

    多表连接时,使用表的别名并把别名前缀于每个Column上。可以减少解析的时间并减少那些由Column 歧义引起的语法错误.

    where子句--执行顺序为自下而上、从右到左

    ORACLE 采用自下而上从右到左的顺序解析Where 子句,根据这个原理,表之间的连接必须写在其他Where 条件之前, 可以过滤掉最大数量记录的条件必须写在Where 子句的末尾。

     

    group by--执行顺序从左往右分组

    提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。即在GROUP BY前使用WHERE来过虑,而尽量避免GROUP BY后再HAVING过滤。

     

    having 子句----很耗资源,尽量少用

    避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作.

    如果能通过Where 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销.
    (非oracle 中)on、where、having 这三个都可以加条件的子句中,on 是最先执行,where 次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,

    where 也应该比having 快点的,因为它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where 跟having比较了。

    在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上后者要慢。
    如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,where 的作用时间是在计算之前就完成的,而having 就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。

    在多表联接查询时,on 比where 更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where 进行过滤,然后再计算,计算完后再由having 进行过滤。

    由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。

     

    select子句--少用*号,尽量取字段名称。

    ORACLE 在解析的过程中, 会将依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 使用列名意味着将减少消耗时间。

    sql 语句用大写的;因为 oracle 总是先解析 sql 语句,把小写的字母转换成大写的再执行

    order by子句--执行顺序为从左到右排序,很耗资源

    展开全文
  • 如果是对MySQL整个表数据导出,可以参照文章:http://www.crazyant.net/1355.html然而也会遇到的场景是,需要执行一个SQL语句,然后将SQL语句结果输出到文件;...举个例子,执行以下的SQL语句:1mysql -h10.10....

    如果是对MySQL整个表数据导出,可以参照文章:http://www.crazyant.net/1355.html

    然而也会遇到的场景是,需要执行一个SQL语句,然后将SQL语句的结果输出到文件;

    方法一:使用MySQL的select * into outfile ‘/tmp/rs.txt’ from tb_name句型

    这是个不可行的方法;

    举个例子,执行以下的SQL语句:

    这个SQL总会报出下面的错误:

    原因是这个语句并不是在MySQL客户端,而是在MySQL的服务器上执行的,通常用于服务器管理员在服务器机器上进行数据备份使用,由于MySQL客户端账号并没有访问服务器机器本身的权限,所以这个SQL执行不会成功。

    方法2:直接将SQL执行的结果重定向到文件即可

    执行下面的命令,能够将SQL语句执行的结果输出到文件:

    其中-Ne是执行这个SQL语句的选项,-N代表输出SQL语句执行结果中不带第一行的字段名称,-e表示要执行SQL语句;

    执行下面的命令,则可以执行SQL文件,并把结果输出到文件:

    新建一个文件,名称为runsql.sql,内容为:

    然后这样执行命令:

    其中-N命令仍然表示不输出表头字段说明(第一行),小于号表示输入重定向,runsql.sql的文件内容会被发送给mysql的命令,大于号则表示输出重定向,会将命令执行的结果输出到文件;


    导出csv文件,逗号分隔符:

    1
    mysql - h10 . 10.10.10 - ucrazyant - p123456 - P3306 - N < runsql . sql | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > / tmp / rs . txt

    总结:

    • select into outfile只能在MySQL服务器上执行,客户端上无法执行;
    • mysql -Ne “sql” > rs.txt可以将SQL语句执行后输出为文件
    • mysql -N < runsql.sql > rs.txt可以执行sql文件中的内容,然后将结果输出到文件;
    • mysql -N的选项,表示输出时不带表头
    展开全文
  • hive语句执行顺序

    千次阅读 2017-10-27 21:54:03
    SQL语句书写顺序: select … from… where….... MySQL语句执行顺序: from… where… group by… having…. select … order by… hive语句执行顺序: from… where… select… group by… having … ord
  • 执行SQL语句 方法一: 语法: 调用ibm_db.prepare()函数并传递以下参数: 1.从ibm_db.connect()或ibm_db.pconnect()函数返回的有效数据库连接资源; 2.包含SQL语句的字符串,包括需要变量输入的任何列或谓词值的...
  • MySQL的语句执行情况

    千次阅读 2018-07-31 21:01:04
    下面是对查询语句执行情况的方法介绍。   一、设置STATISTICS STATISTICS选项有PROFILE,IO ,TIME。 SET STATISTICS PROFILE ON:显示每个查询执行后的结果集,代表查询执行的配置文件。 SET STATISTICS IO.....
  • 查看sql语句执行时间或测试sql语句性能
  • SQL 语句执行时间分析

    千次阅读 2015-09-02 17:58:17
    以下语句可以进行SQL 语句执行时间分析 use Work--数据库名 go set statistics profile on set statistics io on set statistics time on go -----(SQL执行语句) go set statistics profile off set statistics io...
  • for循环语句执行顺序

    千次阅读 2019-05-07 15:22:28
    for循环在编程中经常遇到,这里我们探究一下其中语句执行顺序,以更加准确的确定 代码演示 结构说明for (a初始条件; b循环判断条件; c循环过程表达式) { d循环体 } a.初始条件:对刚开始执行循环体做...
  • Oracle select语句执行顺序

    千次阅读 2016-08-21 20:34:35
    oracle select语句执行顺序及各部分功能详解
  • 不管你是刚学习软件开发的初学者,还是在IT职场打拼多年的职场老鸟,都免不了要同各种数据库打交道,你可能会碰到以下几个问题:1、感觉自己写的sql语句没有错,但是执行结果总是不对;2、某个功能执行语句知道有...
  • 判断sql执行语句结果为空集

    千次阅读 2014-05-06 13:15:06
    String sql = “select count(*) as num from user ” 判断 if(rs.next()){ System.out.print("有了"); }else{ System.out.print("没了"); }
  • MySQL查询语句执行的过程

    千次阅读 2016-09-01 19:38:05
    背景 介绍MySQL语句执行select的过程过程概览 客户端发送一条查询给服务器; 服务器先会检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段; 服务器端进行SQL解析、预处理,再由优化器...
  • SQL 查询语句执行 SELECT?兄弟你认真的么?

    万次阅读 多人点赞 2020-05-02 19:57:21
    SQL 查询的执行顺序是怎样的? 好像这个问题应该很好回答,毕竟自己已经写了无数个 SQL 查询了,有一些还很复杂的。还装不了这个逼了?! 但事实是,我仍然很难确切地说出它的顺序是怎样的。 言归正传,...
  • 接着上一篇文章《Oracle调用接口(OCI)源码剖析(1):创建数据库连接》,我们继续对OCI中执行SQL语句并获取结果的源码进行剖析。该操作主要是由两个函数完成的:CDbExecSql和CDbFetch,其中CDbExecSql函数用于执行普通...
  • Mysql查询语句执行过程及运行原理

    万次阅读 多人点赞 2018-10-22 22:36:21
    Mysql查询语句执行原理 数据库查询语句如何执行? DML语句首先进行语法分析,对使用sql表示的查询进行语法分析,生成查询语法分析树。 语义检查:检查sql中所涉及的对象以及是否在数据库中存在,用户是否具有操作...
  • hive语句执行顺序msyql语句执行顺序代码写的顺序:select ... from... where.... group by... having... order by.. 或者 from ... select ... 代码的执行顺序:from... where...group by... having.... select .....
  • 一,通过设置STATISTICS我们可以查看执行SQL时的系统情况。...SET STATISTICS IO ON:报告与语句内引用的每个表的扫描数、逻辑读取数(在高速缓存中访问的页数)和物理读取数(访问磁盘的次数)有关的信息。  SE
  • return语句执行流程详解

    千次阅读 2018-07-13 09:02:10
    今天去逛论坛 时发现了一个很有趣的问题: 谁能给我我解释一下这段程序的结果为什么是:2.而不是:3 代码如下: class Test { public int aaa() { int x = 1; try { return ++x;...
  • 查看sql语句执行时间

    千次阅读 2009-07-09 13:22:00
    资料来自于:http://technet.microsoft.com/zh-cn/library/ms187735(SQL.90).aspx SET SHOWPLAN_ALL (Transact-SQL) 使 Microsoft SQL Server 不执行 Transact-SQL 语句。SQL Server 返回有关语句执行情况的详细信
  • SQL语句执行顺序 SQL语句执行顺序 结合上图,整理出如下伪SQL查询语句。 SQL语句执行顺序 从这个顺序中我们可以发现,所有的查询语句都是从FROM开始执行的。在实际执行过程中,每个步骤都会为下一个步骤...
  • mysql中explain查看sql语句执行效率

    千次阅读 2016-12-27 14:54:45
    explain显示了MySQL如何使用索引来处理select语句以及...这个不重要,查询序号即为sql语句执行的顺序 select_type select类型,它有以下几种值  simple 它表示简单的select,没有union和子查询  primary 最外面的sel
  • 对于 if-else 语句,它是 单条件双分支语句,即程序的执行流程是根据 一个条件来控制的; 如下代码演示了存在多个 if - else 时的执行顺序: int test11 = 2; if (test11 > 1) { // if语句判断 int test...
  • Mysql----SQL查询语句执行顺序

    千次阅读 2016-08-22 16:17:17
    SQL查询语句执行顺序
  • MySQL查看SQL语句执行效率

    万次阅读 2013-04-08 13:22:30
    SQL 语句执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。 Explain语法:explain select … from … [where ...] 例如:explain select * from news; 输出:
  • SQL语句执行流程与顺序原理解析

    千次阅读 2015-05-20 22:56:53
    Oracle语句执行流程 第一步:客户端把语句发给服务器端执行 当我们在客户端执行SQL语句时,客户端会把这条SQL语句发送给服务器端,让服务器端的进程来处理这语句。也就是说,Oracle 客户端是不会做任何的操作...
  • sql语句执行顺序以及流程(分分钟掌握版)

    万次阅读 热门讨论 2018-03-07 10:13:26
    程序员对sql语句执行顺序的透彻掌握,是避免编程中各种bug和错误,歧义语句的不二法则。SELECT DISTINCT &lt;select_list&gt; FROM &lt;left_table&gt; &lt;join_type&gt; JOIN &lt;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 778,640
精华内容 311,456
关键字:

以下语句的执行结果是