努比亚z17是不荣耀9是曲面屏吗

6816人阅读
SQL TUNING(67)
今天优化了一个分页的SQL,以前虽然做了上千个SQL的优化,不过都是一些OLAP的,虽然也有OLTP的不过从来没做过分页优化,所以这里记录一下。
SQL和执行计划如下:
SQL& SELECT A.ROWNO,EMS_EVENT_VIEW.* FROM EMS_EVENT_VIEW,
(SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY first_occurrence_time DESC) AS ROWNO,EVENT_ID
FROM EMS_EVENT_VIEW
WHERE (first_occurrence_time&to_date(' 00:00:00','yyyy-mm-dd hh24:mi:ss')
and first_occurrence_time&to_date(' 09:42:35','yyyy-mm-dd hh24:mi:ss'))
or (last_occurrence_time&to_date(' 00:00:00','yyyy-mm-dd hh24:mi:ss')
and last_occurrence_time&to_date(' 09:42:35','yyyy-mm-dd hh24:mi:ss')))
WHERE ROWNO&=0 AND ROWNO&=20) A
WHERE EMS_EVENT_VIEW.EVENT_ID=A.EVENT_ID;
Plan hash value:
-------------------------------------------------------------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Operation
| Starts | E-Rows | A-Rows |
| Buffers |
1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------------------
0 | SELECT STATEMENT
20 |00:00:53.37 |
20 |00:00:53.37 |
1179K| 6598K (0)|
20 |00:00:30.83 |
WINDOW SORT PUSHED RANK
21 |00:00:30.83 |
4096 | 4096
| EMS_EVENT_VIEW
CONCATENATION
0 |00:00:00.01 |
TABLE ACCESS BY INDEX ROWID| EMS_EVENT
0 |00:00:00.01 |
INDEX RANGE SCAN
| LAST_OCCURRENCE_TIME_INDEX
0 |00:00:00.01 |
TABLE ACCESS BY INDEX ROWID| EMS_EVENT
0 |00:00:00.01 |
INDEX RANGE SCAN
| FIRST_OCCURRENCE_INDEX
0 |00:00:00.01 |
| index_join_006
PARTITION RANGE ALL
INDEX FAST FULL SCAN
| IDX_FIRSTTIME_201202
PARTITION RANGE ALL
INDEX FAST FULL SCAN
| IDX_LASTOCCURRENCE_201202
INDEX FAST FULL SCAN
| PK_EMS_EVENT_HISTORY_201202 |
| EMS_EVENT_VIEW
TABLE ACCESS FULL
| EMS_EVENT
PARTITION RANGE ALL
TABLE ACCESS FULL
| EMS_EVENT_HISTORY
-------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access(&EMS_EVENT_VIEW&.&EVENT_ID&=&from_subquery_003&.&EVENT_ID&)
2 - filter((&ROWNO&&=:SYS_B_8 AND &ROWNO&&=:SYS_B_9))
3 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION(&FIRST_OCCURRENCE_TIME&) DESC )&=:SYS_B_9)
4 - filter(:SYS_B_8&=:SYS_B_9)
9 - access(&A&.&LAST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_4,:SYS_B_5) AND &A&.&LAST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_6,:SYS_B_7))
10 - filter((LNNVL(&A&.&LAST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_6,:SYS_B_7)) OR LNNVL(&A&.&LAST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_4,:SYS_B_5))))
11 - access(&A&.&FIRST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_0,:SYS_B_1) AND &A&.&FIRST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_2,:SYS_B_3))
12 - filter(((&B&.&FIRST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_0,:SYS_B_1) AND &B&.&FIRST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_2,:SYS_B_3)) OR
(&B&.&LAST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_4,:SYS_B_5) AND &B&.&LAST_OCCURRENCE_TIME&&TO_DATE(:SYS_B_6,:SYS_B_7))))
13 - access(ROWID=ROWID)
14 - access(ROWID=ROWID)
&如果你看不清楚SQL,我在这里再贴一下:
SELECT A.ROWNO, EMS_EVENT_VIEW.*
& FROM EMS_EVENT_VIEW,
&&&&&& (SELECT *
&&&&&&&&& FROM (SELECT ROW_NUMBER() OVER(ORDER BY first_occurrence_time DESC) AS ROWNO,
&&&&&&&&&&&&&&&&&&&&&& EVENT_ID
&&&&&&&&&&&&&&&&& FROM EMS_EVENT_VIEW
&&&&&&&&&&&&&&&& WHERE (first_occurrence_time &
&&&&&&&&&&&&&&&&&&&&&& to_date(' 00:00:00',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 'yyyy-mm-dd hh24:mi:ss') and
&&&&&&&&&&&&&&&&&&&&&& first_occurrence_time &
&&&&&&&&&&&&&&&&&&&&&& to_date(' 09:42:35',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 'yyyy-mm-dd hh24:mi:ss'))
&&&&&&&& WHERE ROWNO &= 0
&&&&&&&&&& AND ROWNO &= 20) A
&WHERE EMS_EVENT_VIEW.EVENT_ID = A.EVENT_ID;
这个SQL其实就是一个分页SQL,利用 row_number over 做分页,EMS_EVENT_VIEW是一个视图。这个SQL确实写得很坑爹,它要扫描EMS_EVENT_VIEW两次,其实我们可以改写它,让它扫描一次,而不是自己和自己利用event_id 做自连接。
EMS_EVENT_VIEW的定义就不贴出来了,涉及保密&。它的大概意思就是 select * from a union all select * 无where 过滤条件。
&因为这个SQL是朋友给我的,我无法连接到他的DB,所以我只有自己做测试了,测试代码如下:
create table a as select * from dba_
create table b as select * from dba_
create view test_view as select * from a
union all select *
create index idx_a on a(created ,last_ddl_time);
create index idx_b on b(created ,last_ddl_time);
& DBMS_STATS.GATHER_TABLE_STATS(ownname&&&&&&&&& =& 'SCOTT',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& tabname&&&&&&&&& =& 'B',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& estimate_percent =& 100,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& method_opt&&&&&& =& 'for all columns size auto',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& no_invalidate&&& =& FALSE,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& degree&&&&&&&&&& =& 4,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& cascade&&&&&&&&& =& TRUE);
& DBMS_STATS.GATHER_TABLE_STATS(ownname&&&&&&&&& =& 'SCOTT',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& tabname&&&&&&&&& =& 'B',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& estimate_percent =& 100,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& method_opt&&&&&& =& 'for all columns size auto',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& no_invalidate&&& =& FALSE,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& degree&&&&&&&&&& =& 4,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& cascade&&&&&&&&& =& TRUE);
要优化的SQL可以改写成如下代码,只访问一次视图:
select * from&
select t.*,rownum rn from&
(select /*+ INDEX(TEST_VIEW.A idx_a) INDEX(TEST_VIEW.b idx_b) */ *
& from test_view
&where created & to_date('', 'yyyy-mm-dd') or
&&&&&& LAST_DDL_TIME & to_date('', 'yyyy-mm-dd')
&order by created desc&
) t where rownum&=20
) where rn&=0;
现在来看它的执行计划
SQL& select * from
select t.*,rownum rn from
(select /*+ INDEX(TEST_VIEW.A idx_a) INDEX(TEST_VIEW.b idx_b) */ *
from test_view
where created & to_date('', 'yyyy-mm-dd') or
LAST_DDL_TIME & to_date('', 'yyyy-mm-dd')
order by created desc
) t where rownum&=20
) where rn&=0;
已选择20行。
00: 00: 00.10
----------------------------------------------------------
Plan hash value:
-------------------------------------------------------------------------------------------------------
| Operation
| Bytes |TempSpc| Cost (%CPU)| Time
-------------------------------------------------------------------------------------------------------
0 | SELECT STATEMENT
(2)| 00:00:23 |
(2)| 00:00:23 |
COUNT STOPKEY
(2)| 00:00:23 |
SORT ORDER BY STOPKEY
(2)| 00:00:23 |
| TEST_VIEW | 70304 |
(5)| 00:00:04 |
UNION-ALL PARTITION
TABLE ACCESS BY INDEX ROWID| A
(3)| 00:00:03 |
INDEX FULL SCAN
(4)| 00:00:03 |
TABLE ACCESS BY INDEX ROWID| B
(3)| 00:00:03 |
INDEX FULL SCAN
(4)| 00:00:03 |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(&RN&&=0)
2 - filter(ROWNUM&=20)
4 - filter(ROWNUM&=20)
8 - filter(&CREATED&&TO_DATE(' 00:00:00', 'yyyy-mm-dd hh24:mi:ss') OR
&LAST_DDL_TIME&&TO_DATE('','yyyy-mm-dd'))
10 - filter(&CREATED&&TO_DATE(' 00:00:00', 'yyyy-mm-dd hh24:mi:ss') OR
&LAST_DDL_TIME&&TO_DATE('','yyyy-mm-dd'))
----------------------------------------------------------
recursive calls
db block gets
consistent gets
physical reads
bytes sent via SQL*Net to client
bytes received via SQL*Net from client
SQL*Net roundtrips to/from client
sorts (memory)
sorts (disk)
rows processed
逻辑读566,那么这样改写是不是最优化的呢?显然不是,因为索引 IDX_A,IDX_B 都是走的 index full scan,会扫描整个索引block,原始的SQL这个索引里面有3863K 条数据,性能肯定是很低的。 所以进一步的 改写SQL 如下:
select * from
select t.*,rownum rn from
select * from
(select * from
select /*+ index_desc(a) */ *
&where created & to_date('', 'yyyy-mm-dd') or
&&&&&& LAST_DDL_TIME & to_date('', 'yyyy-mm-dd')
&order by created desc&
) where rownum&=20
select * from
select /*+ index_desc(b) */ *
&where created & to_date('', 'yyyy-mm-dd') or
&&&&&& LAST_DDL_TIME & to_date('', 'yyyy-mm-dd')
&order by created desc&
) where rownum&=20
) order by created desc
) t where rownum&=20
) where rn&=0
执行计划和逻辑读如下:
SQL& select * from
select t.*,rownum rn from
select * from
(select * from
select /*+ index_desc(a) */ *
where created & to_date('', 'yyyy-mm-dd') or
LAST_DDL_TIME & to_date('', 'yyyy-mm-dd')
order by created desc
) where rownum&=20
select * from
select /*+ index_desc(b) */ *
where created & to_date('', 'yyyy-mm-dd') or
LAST_DDL_TIME & to_date('', 'yyyy-mm-dd')
order by created desc
) where rownum&=20
) order by created desc
) t where rownum&=20
) where rn&=0;
已选择20行。
00: 00: 00.04
----------------------------------------------------------
Plan hash value:
---------------------------------------------------------------------------------------------
| Operation
| Bytes | Cost (%CPU)| Time
---------------------------------------------------------------------------------------------
0 | SELECT STATEMENT
(4)| 00:00:03 |
(4)| 00:00:03 |
COUNT STOPKEY
(4)| 00:00:03 |
SORT ORDER BY STOPKEY
(4)| 00:00:03 |
(3)| 00:00:03 |
COUNT STOPKEY
(3)| 00:00:03 |
TABLE ACCESS BY INDEX ROWID| A
(3)| 00:00:03 |
INDEX FULL SCAN DESCENDING| IDX_A |
(4)| 00:00:03 |
COUNT STOPKEY
(0)| 00:00:01 |
TABLE ACCESS BY INDEX ROWID| B
(0)| 00:00:01 |
INDEX FULL SCAN DESCENDING| IDX_B |
(0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(&RN&&=0)
2 - filter(ROWNUM&=20)
4 - filter(ROWNUM&=20)
7 - filter(ROWNUM&=20)
10 - filter(&CREATED&&TO_DATE(' 00:00:00', 'yyyy-mm-dd hh24:mi:ss') OR
&LAST_DDL_TIME&&TO_DATE('','yyyy-mm-dd'))
11 - filter(ROWNUM&=20)
14 - filter(&CREATED&&TO_DATE(' 00:00:00', 'yyyy-mm-dd hh24:mi:ss') OR
&LAST_DDL_TIME&&TO_DATE('','yyyy-mm-dd'))
----------------------------------------------------------
recursive calls
db block gets
consistent gets
physical reads
bytes sent via SQL*Net to client
bytes received via SQL*Net from client
SQL*Net roundtrips to/from client
sorts (memory)
sorts (disk)
rows processed
逻辑读整整下降了60倍。
现在根据这个案例来谈谈SQL分页的优化思路,SQL分页通常要进行排序,比如select xxxx from t where 条件 order by ......
优化分页SQL可以重点关注 order by 这个条件,写SQL的时候要让ORACLE 对 order by 列 上的索引进行有序的扫描,然后根据stopkey 停止,也就是不要把索引的block全都给扫描了,应该扫描一部分block就停止。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1076953次
积分:13088
积分:13088
排名:第849名
原创:202篇
评论:581条
(1)(1)(1)(1)(1)(1)(1)(2)(1)(3)(1)(1)(3)(2)(1)(1)(1)(2)(2)(1)(1)(1)(1)(2)(1)(1)(1)(1)(4)(2)(2)(4)(1)(4)(4)(8)(1)(2)(2)(1)(2)(2)(1)(1)(3)(3)(4)(14)(7)(3)(38)(28)(25)24550人阅读
Technology(14)
分页技术原理与实现(一)&&为什么要进行分页及怎么分页
什么是分页技术
分页,是一种将所有数据分段展示给用户的技术.用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自习自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止.其实这和我们阅读书籍很类似.
&下页显示了两种常见的分页方式:
分页的意义
分页确实有效,但它一定会加大系统的复杂度,但可否不分页呢?如果数据量少的话当然可以.但是对于企业信息系统来说数据量不会限制在一个小范围内.如果不顾一切的Select * from某个表,再将返回的数据一古脑的扔给客户,即使客户能够忍受成千上万足够让人眼花缭乱的表格式数据,繁忙的网络,紧张的服务器也会提出它们无声的抗议,甚至有时会以彻底的罢工作为终结.这个结局有点像古代为所欲为的暴君和他忍无可忍的臣民之间的故事.& 程序员不是暴君,他希望程序使生活变得更好而不是更糟.考虑到企业信息系统多是三层甚至更多层架构的事实,程序员在向客户展示数据时都应该采取分页的形式.如果他不想被抱怨淹没或是半夜被电话惊醒的话.
从请求发起到返回数据的整个过程
现在你已经下定决心想要分页了,在动手书写代码之前,先让我们回想一下,在典型的三层架构中,从请求发起到返回数据的整个过程.如下所示:
在哪里进行分页
从上面的图中我们可以观察得知,在SQL语句处理完毕后,数据库,WebApplication和Browser都能进行分页,那在哪里分页好呢?& 判断的标准是速度,显而易见,数据库服务器,Web应用服务器和客户端之间是网络,如果网络传递的数据量越少,则客户端获得响应的速度越快.而且一般来说,数据库服务器和Web应用服务器的处理能力一般比客户端要强很多.从这两点来看,在客户端分页的方案是最不可取的.& 其次就剩下了在Web服务器端分页和在数据库端分页两种方式了,如果选择在Web服务器端分页的话,大部分的被过滤掉的数据还是被传输到了Web应用服务器端,与其这样还不如直接在数据库端进行分页.
因此比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。
分页的SQL语句
如果我们是通过JDBC的方式访问数据库,那么就有必要根据数据库类型采取不同的SQL分页语句,对于MySql数据库,我们可以采用limit语句进行分页,对于Oracle数据库,我们可以采用rownum的方式进行分页.
(1)MySql的Limit m,n语句
Limit后的两个参数中,参数m是起始下标,它从0开始;参数n是返回的记录数。我们需要分页的话指定这两个值即可
(2)Oracle数据库的rownum
在Oracle数据库中,分页方式没有MySql这样简单,它需要依靠rownum来实现.Rownum表示一条记录的行号,值得注意的是它在获取每一行后才赋予.因此,想指定rownum的区间来取得分页数据在一层查询语句中是无法做到的,要分页还要进行一次查询.
SELECT * FROM (SELECT A.*, ROWNUM RN FROM (SELECT * FROM TABLE_NAME) A WHERE ROWNUM &= 40)WHERE RN &= 21
其中最内层的查询SELECT * FROM TABLE_NAME表示不进行翻页的原始查询语句。ROWNUM &= 40和RN &= 21控制分页查询的每页的范围。
上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。在上面的分页查询语句中,这种考虑主要体现在WHERE ROWNUM &= 40这句上。
选择第21到40条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过ROWNUM &= 40来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHERE ROWNUM &= 40语句,在查询的最外层控制分页的最小值和最大值。这是,查询语句如下:
SELECT * FROM (SELECT A.*, ROWNUM RN FROM (SELECT * FROM TABLE_NAME) A )WHERE RN BETWEEN 21 AND 40
对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。
这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM &= 40就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。
而第二个查询语句,由于查询条件BETWEEN 21 AND 40是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)。因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。
上面分析的查询不仅仅是针对单表的简单查询,对于最内层查询是复杂的多表联合查询或最内层查询包含排序的情况一样有效。
附:分页技术实现:
附:Oracle分页查询:
附:使用 PHP 和 Oracle 实施分页结果集:/technology/global/cn/pub/articles/oracle_php_cookbook/fuecks_paged.html
其实分页技术还有很多其它技术,比如:Struts、Hibernate等等都可实现。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:103565次
积分:1300
积分:1300
排名:千里之外
原创:24篇
评论:88条
(3)(1)(1)(3)(2)(2)(2)(2)(2)(4)(4)(1)急!求大神教uc怎么搞分页_uc吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:2,335,296贴子:
急!求大神教uc怎么搞分页收藏
就是那种漫画不用点击下一页就能直接把图片加载在下面的。。我的有时候可以有时候就是说是最后一张了。。。求告诉怎么办
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或

我要回帖

更多关于 小米note3有边框吗 的文章

 

随机推荐