在做分页查询时,进行到最后一页时用时大概20秒左右,其他页只有0.3秒左右,下面附上语句,请高人帮忙看看是什么问题?select uidused,pid,ekuid,s1sid,flag from(select rownum rnm ,a.* from(select * from tab_test
where 1=1 and flag!=5 and systemtime>=to_date('2008-3-11 11:8:15','yyyy-mm-dd hh24:mi:ss') and ststem<=to_date('2008-6-11 11:8:15','yyyy-mm-dd hh24:mi:ss') order by uidused desc) a where rownum<=29010 )where rnm>=28996//该语句是执行查询最后一页时打印出的SQL语句。下面是执行倒数第二页时的查询语句:
select uidused,pid,ekuid,s1sid,flag from(select rownum rnm ,a.* from(select * from tab_test
where 1=1 and flag!=5 and systemtime>=to_date('2008-3-11 11:8:15','yyyy-mm-dd hh24:mi:ss') and ststem<=to_date('2008-6-11 11:8:15','yyyy-mm-dd hh24:mi:ss') order by uidused desc) a where rownum<=28995 )where rnm=>28981
附录:每页15条数据,数据库中共有45万条数据。表tab_test的主键为UIDUSED,在PID上也建有索引。只有执行最后一页查询时才比较缓慢,其他页查询非常快,请高手不吝赐教
where 1=1 and flag!=5 and systemtime>=to_date('2008-3-11 11:8:15','yyyy-mm-dd hh24:mi:ss') and ststem<=to_date('2008-6-11 11:8:15','yyyy-mm-dd hh24:mi:ss') order by uidused desc) a where rownum<=29010 )where rnm>=28996//该语句是执行查询最后一页时打印出的SQL语句。下面是执行倒数第二页时的查询语句:
select uidused,pid,ekuid,s1sid,flag from(select rownum rnm ,a.* from(select * from tab_test
where 1=1 and flag!=5 and systemtime>=to_date('2008-3-11 11:8:15','yyyy-mm-dd hh24:mi:ss') and ststem<=to_date('2008-6-11 11:8:15','yyyy-mm-dd hh24:mi:ss') order by uidused desc) a where rownum<=28995 )where rnm=>28981
附录:每页15条数据,数据库中共有45万条数据。表tab_test的主键为UIDUSED,在PID上也建有索引。只有执行最后一页查询时才比较缓慢,其他页查询非常快,请高手不吝赐教
解决方案 »
- 帮忙看一个存储过程的问题
- 对于不同用户、不同session,oracle分配的资源是一样的吗?
- oracle登陆的问题
- ora-04031 Error windows补丁在什么地方可以下载???
- 求助:ADO方式oracle参数化查询出错,提示未传入参数
- 如何查询id最小的记录?
- 紧急求救,紧急!!!!!给100分
- 创建视图时,遇到一个问题,字段的求和不能得到
- oracle+pb开发,没有用到大名鼎鼎的pl/sql啊!
- 那位大侠做过oracle从unix到linux的数据迁移????
- 如何将同一个数据库中不用用户可见的表进行insert 操作?
- 如何PL-SQL中SQL WINDOW 执行字符串型SQL
8i是rbo,10g是cbo,策略不一样你是在应用里测试的反应时间,
还是把sql语句放在sql/plus下执行得出的时间?要是在应用里测量的,那么可能就是编码的问题
如果是在sql/plus下执行的,你可以把统计信息贴出来让大家看看
SQL> set autot trace statSQL> execute dbms_stats.gather_table_stats('SCOTT','T2') ;PL/SQL 过程已成功完成。SQL> execute dbms_stats.gather_INDEX_stats('SCOTT','I2');PL/SQL 过程已成功完成。SQL> select count(*) from T2; COUNT(*)
----------
229376
执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=308 Card=1)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=308 Card=23226
9)统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
1397 consistent gets
1379 physical reads
1052 redo size
397 bytes sent via SQL*Net to client
512 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
差不多就是这个样子, I2是T2上的索引
搜集了先,再看执行计划
order by 的话,可以把rownum <=29010放在最里面的where里,即order by 的前面此方法仅对用主键排序的有效
会比你放在外层的要快的假设你最里层的where 过滤后有40万纪录,这两种写法的差别rownum <=29010 直接出来29010条,然后再把<28996的过滤掉
然后放在第二层的话,就会最里层仍然出来40万条,然后再过滤掉29010条之后的,然后过滤之前的
而走cbo的话,就会和数据分布有关系了
网上很多人都记错了SQL> select * from product_component_version;
PRODUCT VERSION
-------------------------------------------------- -----------
NLSRTL 10.1.0.2.0
Oracle Database 10g Enterprise Edition 10.1.0.2.0
PL/SQL 10.1.0.2.0
TNS for 32-bit Windows: 10.1.0.2.0 SQL> show parameter optimizer_modeNAME TYPE VALUE
------------------------------------ ----------- ----------
optimizer_mode string ALL_ROWS
Oracle是能够灵活调整执行计划的all_rows策略在当时数据库的环境下, 会尽量选择占用资源较少的执行方案
而改用first_row策略,会选用返回数据较快的方案,
所以一切都要看了执行计划后才方便做具体的调优, 但是你一直没贴上来
靠猜测是不可靠的啊你昨天做测试时收集统计信息了没? 今天呢?
另外你可以尝试使用下first_rows看看性能如何
2 /会话已更改。SQL> show parameter optimizer_modeNAME TYPE VALUE
------------------------------------ --------------- -------------
optimizer_mode string FIRST_ROWS
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
10159 consistent gets
3831 physical reads
0 redo size
941 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
3 rows processed
倒数第二页统计信息:
统计信息
----------------------------------------------------------
188 recursive calls
0 db block gets
10207 consistent gets
1517 physical reads
0 redo size
2105 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
15 rows processed第一页统计信息:
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
2105 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed
优化后语句:select uidused,pid,ekuid,s1sid,flag from(select rownum rnm ,uidused,pid,ekuid,s1sid,flag from tab_test
where 1=1 and flag!=5 and systemtime>=to_date('2008-3-11 11:8:15','yyyy-mm-dd hh24:mi:ss') and systemtime <=to_date('2008-6-11 11:8:15','yyyy-mm-dd hh24:mi:ss')
and rownum <=29010 order by uidused desc)where rnm>=28996
该优化主要是将rownum <=29010移到了order by前面,而且去掉了用*查询和一个子句查询最后一页查询
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
10159 consistent gets
1198 physical reads
0 redo size
941 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
3 rows processed
1:频繁的数据库查询导致查询性能下降。数据库中共有近50万条数据,本论题的条件拣选出28998条记录,每次查询15条,连续数据库查询1934次!
2:使用优化后的语句,见我上条恢复中最后所写语句,系统刚开始查时效率非常高,但查出4000多条时,性能急剧下降,每页(15条)查询平均耗时2秒!到最后一页仍然用时20多秒,可见优化的效果有限。疑惑: 1:在PLSQL里执行最后一页数据的查询语句,耗时2秒左右,但在JAVA程序里执行到最后一页数据查询时却耗时20多秒?如果是因为数据库性能下降,那倒数第二页才用两秒,为什么最后一页就用了十倍于前一页的时间呢?与PLSQL里执行的效果也相差甚远啊!
我用优化后的语句在程序里执行,其实也就是连续查询,到最后一页时仍然执行了20多秒,导致客户端超时。比较疑惑为什么在PLSQL里执行只用2秒,在程序里最后执行时却用了20多秒?
你这15条纪录是否不太一样
最好能贴一下你的表结构上次看过一篇贴子,是同样的语句出来的时间相差很大
结果后来有人分析出来,是数据结构的问题
因为有blob字段,然后又是用select * 去查的,所以同样的语句查不同数据行,会时间上相差很大,主要就是物理读取时间上主要就是字段里的内容读取很费时间
pga的设置了,是不否设置过小,引起连续查询后,性能急剧下降
uidused VARCHAR2(20) NOT NULL,
pid VARCHAR2(20) NOT NULL,
ekuid VARCHAR2(40) NULL,
s1sid VARCHAR2(32) NULL,
flag INTEGER NULL,
);
ALTER TABLE tab_test( ADD PRIMARY KEY (uidused);
CREATE INDEX tab_test_idx1( ON tab_test(pid);
那只能说是瞎猜了,看看oracle的设置是不是会造成大量数据查询后性能下降,SGA,PGA的设置看下下,不过这个我基本不懂,要找个有经验的DBA来看了
SQL> select count(*) from scott.t1; COUNT(*)
----------
229376
执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=301 Card=1)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=301 Card=22962
2)统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
1355 consistent gets
1350 physical reads
0 redo size
397 bytes sent via SQL*Net to client
512 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed单纯从你的统计信息来看,可以发现一个问题,你的recursive calls没有为0情况,有一处甚至达到了188,
那就是说,每次执行SQL时都在做硬解析
虽然你没有加上执行时间,但我可以断定,188的这一处肯定是不快的而且我怀疑,你根本不容易确定查询时哪一页时最慢,
因为你不知道shared_pool什么时候被占满了,满了就会有执行LRU策略出列等操作
当然简单加大shared_pool_size是不可取也是危险的,较大的size会增加oracle的管理难度可以尝试的解决办法是使用绑定变量,当一句sql连续执行两次以上,
它就会在shared_pool_size的队列中占据一个较好的位置,再次执行就会直接从shared_pool中拿来用
查看参数设置的方法是
SQL> show parameter shared_pool_size当然这只是初步的看法,我还需要看下执行计划,我上面的推论也不足以解释所有的疑惑
建议你先使用绑定变量改写sql,再看效果,还不满意的话再贴执行计划和统计信息
------------------------------------ ----------- ------------------------------
shared_pool_size big integer 0
10g的shared_pool_size的大小是自动管理的
如果它分配的空间用完了,会自动缩小缓冲区缓存来增大它你暂且不管这些了,先在你的sql语句里使用绑定变量,避免硬解析,这是必须要做的事情啊
有时会有最后一页快了,其它页慢了的现象出现,不是吗?还有,你的查询是从第一页一直查到最后一页吗? 有没有试过从最后一页查到第一页?
有时间做一下, 顺便贴个执行计划我建议你单纯在sql/plus里测试sql执行时间,这样可以避免考虑别的因素的影响
----------------------------------------------------------
1 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
2105 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed 你第一页的物理读取是0,证明这个结果集被缓存了,而且肯定是软解析,它快是正常的你把数据库关闭,重新装载,只执行最后一页的查询,反复执行多次(在sql/plus里面),看下它是不是也会很快?
这个如果是重启Oracle后在sql/plus里多次执行最后一页sql的结果,
应该可以排除数据库端的问题了你写的sql排列格式太不规整了, 我视力不好看不太清没帮你整, hebo2005的建议是很好的, 你可以根据实际情况调整下
外层尽量先把大量不用的数据过滤掉,里层再做小循环解决不了的话加200分让版主帮忙转到高级技术区去看看,也听听别人意见
SELECT uidused, pid, ekuid, s1sid, flag
FROM (SELECT ROWNUM rnm, a.*
FROM (SELECT *
FROM tab_test
WHERE 1 = 1
AND flag != 5
AND systemtime >=
TO_DATE ('2008-3-11 11:8:15',
'yyyy-mm-dd hh24:mi:ss'
)
AND ststem <=
TO_DATE ('2008-6-11 11:8:15',
'yyyy-mm-dd hh24:mi:ss'
)
ORDER BY uidused DESC) a
WHERE ROWNUM <= 29010)
WHERE rnm >= 28996倒数第二页
SELECT uidused, pid, ekuid, s1sid, flag
FROM (SELECT ROWNUM rnm, a.*
FROM (SELECT *
FROM tab_test
WHERE 1 = 1
AND flag != 5
AND systemtime >=
TO_DATE ('2008-3-11 11:8:15',
'yyyy-mm-dd hh24:mi:ss'
)
AND ststem <=
TO_DATE ('2008-6-11 11:8:15',
'yyyy-mm-dd hh24:mi:ss'
)
ORDER BY uidused DESC) a
WHERE ROWNUM <= 28995)
WHERE rnm >= 28981
优化后的
SELECT uidused, pid, ekuid, s1sid, flag
FROM (SELECT ROWNUM rnm, uidused, pid, ekuid, s1sid, flag
FROM tab_test
WHERE 1 = 1
AND flag != 5
AND systemtime >=
TO_DATE ('2008-3-11 11:8:15', 'yyyy-mm-dd hh24:mi:ss')
AND systemtime <=
TO_DATE ('2008-6-11 11:8:15', 'yyyy-mm-dd hh24:mi:ss')
AND ROWNUM <= 29010
ORDER BY uidused DESC)
WHERE rnm >= 28996
你点到Oracle那个版主的名字bzszp,
然后给他发短信或者及时消息 :
fuck you~~~~
fuck you~~~~
fuck you~~~~
fuck you~~~~
fuck you~~~~他很快就会给你转过去了 (:
fuck you~~~~ 是我联系他的暗号