传统读取数据的方式是服务器进程通过读取磁盘,然后把数据加载到共享内存中,这样后面的进程就可以通过共享内存访问这些数据,不用再通过缓慢的磁盘读取来 完成。direct path read读取数据块方式,是指服务器进程直接读取数据文件,不经过buffer cache,这种方式读取的数据块会加载到服务器进程的PGA内中当中,不会进入buffer cache中。11G之 前的direct path read主要用于并行查询中,此等待事件的三个参数p1,p2,p3分别代表:file#:文件号,first block#:读取的起始块号,block count:以first block为起点,连续读取的物理块数。而从11G之后,direct path read不仅可用于并行查询,在符合某些条件后,串行的全表扫描也可以利用direct path read方式来完成。这里主要介绍11G direct path read相关的特性。
有一次经历让我印象深刻,那是要对一张大表上一个核心索引进行重建,表的大小几十个G是有的。当时预估了时间(全表扫描+排序)应该十几分钟可以搞定,但 是让我吃惊的是整个重建过程足足搞了快1个小时。不停的查看重新索引会话的等待事件,大多数时候都是db file sequential read,零星的能看到几次db file scattered read,虽然指定的多块读大小为128,但是观察到的p3参数小的可怜。导致索引重建慢的原因不难分析,是由于这个表的不少数据被缓存进了buffer cache中,虽然设置的多块读参数为128,但是由于总是无法读取到符合要求的连续的数据块而让性能大打折扣,这里所谓的符合要求指的是读取的数据块都 不在buffer cache之中。例如:
上面的12个块为一个extent,假设都不在buffer cache中的话,一次物理IO就可以完成,但是由于部分块被cache,而导致总共需要6次的物理IO才行。因此在做全表扫描的情况下,表里的数据一部 分被cache并不见得总是好事。当时我在想,如果可以绕过buffer cache,直接路径读取就好了。11G以后,ORACLE终于推出了这个功能,在全表扫描的时候,如果ORACLE认为这个表足够大,就会启用直接路径读取,而不需要像11G之前,必须先把数据加载到buffer cache。
采用direct path read完成读取的条件
1)表大于_small_table_threshold的参数值设置
Oracle通过隐含参数_small_table_threshold来界定大表小表的临界,Oracle认为对于大表执行直接路径读取的意义比较大, 对于小表通过将其缓存可能受益更大。_small_table_threshold的单位为block。默认为db cache size的2%大小,在实例启动过程中动态决定。11GR2之前,表的大小要是_small_table_threshold参数值的5倍才会采取直接路 径读取方式,11GR2后只需要满足_small_table_threshold定义的大小就会采取直接路径读取。我们可以简单的看一下11GR2下的 一个测试:
create tablespace test datafile '+DG_DATA/test/test.dbf' size 64m segment space management manual;
create table t (v varchar2(100)) pctused 1 pctfree 99 tablespace test;
show parameter small
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
_small_table_threshold integer 3000
CREATE OR REPLACE FUNCTION GET_ADR_TRSH(P_STEP IN NUMBER,
P_START IN NUMBER DEFAULT 0,
P_STOP IN NUMBER DEFAULT NULL)
RETURN NUMBER IS
L_PRD NUMBER;
L_CNT NUMBER;
L_BLOCKS NUMBER := 0;
L_START NUMBER := P_START;
BEGIN
EXECUTE IMMEDIATE 'truncate table t';
LOOP
INSERT /*+ append */
INTO T
SELECT RPAD('*', 100, '*')
FROM DUAL
CONNECT BY LEVEL <= P_STEP + L_START;
COMMIT;
L_BLOCKS := L_BLOCKS + P_STEP + L_START;
L_START := 0;
EXECUTE IMMEDIATE 'alter system flush buffer_cache';
SELECT /*+ full(t) */
COUNT(*)
INTO L_CNT
FROM T;
SELECT VALUE
INTO L_PRD
FROM V$SEGMENT_STATISTICS
WHERE OWNER = USER
AND OBJECT_NAME = 'T'
AND STATISTIC_NAME = 'physical reads direct';
EXIT WHEN(L_PRD > 0 OR L_BLOCKS > NVL(P_STOP, L_BLOCKS));
END LOOP;
RETURN L_BLOCKS - P_STEP;
END;
/
set serveroutput on
DECLARE
L_TRSH NUMBER;
BEGIN
L_TRSH := GET_ADR_TRSH(10, 1500, 4000);
DBMS_OUTPUT.PUT_LINE(L_TRSH);
END;
/
3000
以上的代码大家可以研究一下,我不做详细说明了,大体的意思是不断的增加表大小,观察增加到表上的block有多少时,会采取直接路径读取。我们测试的结 果是3000,刚好和我们定义的_small_table_threshold参数值完全吻合。11GR1的话,经过测试是 _small_table_threshold的5倍的时候才会出现直接路径读取。
但是表的大小并不仅仅是唯一决定是否采用直接路径读取的因素,还有其他两个因素:脏块的比例、表中数据被cache的比例
2)表上的脏块小于表总block数的25%
下面的代码通过不断增加表的脏块数,当达到表脏块数的25%的时候,不在发生直接路径读取事件了。
CREATE OR REPLACE FUNCTION GET_DIRTY_TRSH(P_STEP IN NUMBER,
P_START IN NUMBER DEFAULT 0,
P_STOP IN NUMBER DEFAULT NULL)
RETURN NUMBER IS
L_TRSH NUMBER := 0;
L_PRD NUMBER := 0;
L_CNT NUMBER := 0;
L_START NUMBER := P_START;
BEGIN
EXECUTE IMMEDIATE 'alter system flush buffer_cache';
LOOP
L_TRSH := L_TRSH + P_STEP + L_START;
UPDATE T SET V = V WHERE ROWNUM <= L_TRSH;
COMMIT;
L_START := 0;
SELECT /*+ full(t) */
COUNT(*)
INTO L_CNT
FROM T;
SELECT VALUE
INTO L_CNT
FROM V$SEGMENT_STATISTICS
WHERE OWNER = USER
AND OBJECT_NAME = 'T'
AND STATISTIC_NAME = 'physical reads direct';
EXIT WHEN L_CNT = L_PRD OR L_TRSH > NVL(P_STOP, L_TRSH);
L_PRD := L_CNT;
END LOOP;
RETURN L_TRSH;
END;
/
DECLARE
L_TRSH NUMBER;
BEGIN
L_TRSH := GET_DIRTY_TRSH(1, 350, 4000);
DBMS_OUTPUT.PUT_LINE(L_TRSH);
END;
/
739
我们看到脏块的比例大约达到表块的25%(共3000个表块)的时候,直接路径读消失了。
3)表中的块被cache的比例小于50%的时候
CREATE OR REPLACE FUNCTION GET_CACHED_TRSH(P_START IN NUMBER DEFAULT 0,
P_STEP IN NUMBER DEFAULT 1)
RETURN NUMBER IS
CURSOR L_CUR IS
SELECT /*+ index(t i_t) */
v
FROM T WHERE v='****************************************************************************************************';
L_V VARCHAR2(100);
L_TRSH NUMBER := 0;
L_PRD NUMBER := 0;
L_CNT NUMBER := 0;
L_START NUMBER := P_START;
BEGIN
EXECUTE IMMEDIATE 'alter system flush buffer_cache';
OPEN L_CUR;
LOOP
FOR I IN 1 .. P_STEP + L_START LOOP
FETCH L_CUR
INTO L_V;
END LOOP;
L_TRSH := L_TRSH + P_STEP + L_START;
L_START := 0;
SELECT /*+ full(t) */
COUNT(*)
INTO L_CNT
FROM T;
SELECT VALUE
INTO L_CNT
FROM V$SEGMENT_STATISTICS
WHERE OWNER = USER
AND OBJECT_NAME = 'T'
AND STATISTIC_NAME = 'physical reads direct';
EXIT WHEN L_CNT = L_PRD OR L_CUR%NOTFOUND;
L_PRD := L_CNT;
END LOOP;
CLOSE L_CUR;
RETURN L_TRSH;
END;
/
create index i_t on t (v);
DECLARE
L_TRSH NUMBER;
BEGIN
L_TRSH := GET_CACHED_TRSH(500, 1);
DBMS_OUTPUT.PUT_LINE(L_TRSH);
END;
/
1497
在接近50%(共3000个表块)的表块被cache的时候,直接路径读消失了。
11GR1 |
11GR2 |
备注 |
|
块阀值 |
_small_table_threshold*5 |
_small_table_threshold |
统计信息里记录的表的block数目(11GR2)。 超过此阀值后。 |
Block cache阀值 |
表块的50% |
表块的50% |
少于此阀值 |
脏块阀值 |
表块的25% |
表块的25% |
少于此阀值 |
满足以上条件时,Oracle会进行直接路径读取。
Oracle为直接路径读取设置的三个“门槛”,非常的合理:
第 一个阀值:表大小,太小的表从direct path read中的获益太小。但是特别需要引起你的警惕,如果表上存在统计信息,那么ORACLE会采取表的统计信息中记录的block与 _small_table_threshold的设定值来做比较,而不是表的真实大小(dba_segments中记录的值)。这可能导致一些不是你预期 的情况发生。如果你的统计信息与表的真实情况差异很大,那么你应该仔细考虑可能发生什么样的结果。如果你的表没有统计信息,ORACLE会依据表的真实大 小来决定是否进行direct path read。
第二个阀值:脏块阀值,由于direct path read需要出发一个段的检查点,因此脏块太多,刷新脏块可能会导致IO繁忙
第 三个阀值:表在内存里的cache率,如果cache率很高,那么还是走传统路径更快。direct path read的出现,需要让ORACLE公司的开发人员设计一个单独的结构来存储每个表有多少数据是脏数据,有多少数据被cache。不过这个结构目前还并未 暴露给我们查询。在flush buffer cache后,这个结构被清空。(flush shared_pool并不会被清空)
当你预期一个查询应该会走direct path read,但是却走了传统的路径扫描的时候,应该检查是否违背了这三个前置条件中的一个或几个。不过很多时候,当一个查询“应该”走direct path read但是却没有的时候,你往往无能为力,你能在数据库运行过程中修改表的数据的cache比例吗?不能!你能修改表的脏数据的比例吗?往往也不能,通 过修改表的统计信息中的表块数,可以满足第一个条件,但是如果不满足其他两个条件,依然不能有效。你可以通过flush buffer cache来满足后两个条件,但往往在生产环境中不被允许。我曾经在个人微博(新浪微博:魏兴华-DBA)发布过一个关于索引创建走不上direct path read的微博,现在终于想明白了,不满足第三个条件,表被cache的内容需要低于50%。
direct path read的优势
- 我认为非常重要的,参照我文章开头举得例子,采用直接路径读取后,总能保证读取的块数是多块读参数设置的大小,提高了读取的效率
- 大大的降低了对于latch的使用,进而避免了可能导致的latch竞争(cbc latch等)
- 降低了全表扫描对buffer cache的冲击
- 降低了buffer pin的开销,有可能降低buffer busy waits等相关等待
如何控制direct path read的开关
有两种方法来启用、禁用这个特性。event 10949或者设置隐含参数_serial_direct_read。两种方式都可以在session或system级别设置。
- event 10949设置后,可以禁用direct path read。
每次测试前为了避免脏块和缓冲块对测试的影响,都先将buffer cache清空。我们在session级别测试,system级别的测试方法是一样的,这里就不再赘述。
SQL> alter system flush buffer_cache;
System altered.
SQL> ALTER session SET EVENTS '10949 TRACE NAME CONTEXT FOREVER';
Session altered.
SQL> execute snap_events.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL> set serveroutput on
SQL> execute snap_events.end_snap
---------------------------------------------------------
SID: 2929:DLSP - oracle
Session Events - 08-Sep 10:58:50
Interval:- 18 seconds
---------------------------------------------------------
Event Waits Time_outs Csec Avg Csec Max Csec
----- ----- --------- ---- -------- --------
Disk file operations I/O 17 0 0 .012 0
db file scattered read 1,115 0 96 .086 1
SQL*Net message to client 6 0 0 .000 0
SQL*Net message from client 6 0 1,323 220.444 2,350
PL/SQL procedure successfully completed.
SQL> alter system flush buffer_cache;
System altered.
SQL> ALTER session SET EVENTS '10949 TRACE NAME CONTEXT off';
Session altered.
SQL> execute snap_events.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL> execute snap_events.end_snap
---------------------------------------------------------
SID: 2929:DLSP - oracle
Session Events - 08-Sep 10:59:56
Interval:- 8 seconds
---------------------------------------------------------
Event Waits Time_outs Csec Avg Csec Max Csec
----- ----- --------- ---- -------- --------
db file sequential read 1 0 0 .024 0
direct path read 1113 0 300 .232 1
SQL*Net message to client 5 0 0 .001 0
SQL*Net message from client 5 0 445 89.034 2,673
我们通过snap_events脚本获取了会话执行语句前后等待事件的差值,启用10949事件后,执行了db file scattered read,关闭10949事件后,以direct path read方式进行了表扫描。
2.通过设置隐含参数_serial_direct_read来设置是否启用direct path read,同样我们只在session级别做测试,system级别可以由读者自己来完成。
SQL>alter session set "_serial_direct_read"=false;
Session altered.
SQL> execute snap_events.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL>execute snap_events.end_snap
SQL> ---------------------------------------------------------
SID: 2641:DLSP - oracle
Session Events - 08-Sep 10:49:46
Interval:- 9 seconds
---------------------------------------------------------
Event Waits Time_outs Csec Avg Csec Max Csec
----- ----- --------- ---- -------- --------
Disk file operations I/O 6 0 0 .001 0
db file sequential read 1 0 0 .030 1
db file scattered read 1,115 0 154 .138 4
SQL*Net message to client 5 0 0 .000 0
SQL*Net message from client 5 0 228 45.510 1,912
PL/SQL procedure successfully completed.
SQL> alter session set "_serial_direct_read"=auto;
Session altered.
SQL> alter system flush buffer_cache;
System altered.
SQL> execute snap_events.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL>execute snap_events.end_snap
SQL> ---------------------------------------------------------
SID: 2641:DLSP - oracle
Session Events - 08-Sep 10:50:21
Interval:- 10 seconds
---------------------------------------------------------
Event Waits Time_outs Csec Avg Csec Max Csec
----- ----- --------- ---- -------- --------
db file sequential read 1 0 0 .028 1
direct path read 1112 0 42 .164 0
SQL*Net message to client 5 0 0 .000 0
SQL*Net message from client 5 0 730 146.016 1,912
PL/SQL procedure successfully completed.
_serial_direct_read设置为false后,系统采取了传统的扫描路径,出现了db file scattered read等待时间,_serial_direct_read为true后,采用了direct path read的等待事件。
direct path read可能的副作用
- 会发生段一级的检查点(后面详细介绍),因此在查询真正开始执行前,会做这个额外的准备工作。而且可能会造成IO抖动,因为要写脏数据。
- 如果你的表需要频繁的全表扫描读取,还是用传统的读取方式比较好。
- 在MOS中搜索direct path read,会发现它可能会导致多次的延迟块清除(后面详细介绍)
直接路径读为什么要发生检查点?
Oracle的一致性读取代表的是:读取到的数据是查询开始时刻的数据,在你对一个大表发出查询前,首先需要发生一个段级别的检查点来保证这个段上的脏数据已经被刷新到了磁盘,如果不这样做会发生什么情况?
举个例子就会很容易明白:查询发生时,某条记录的id值在磁盘上的值为5,内存中的值为6。如果不发生段一级的检查点就开 始直接路径读取,那么进程在读取到这个记录所在的数据块后发现,块上的scn是小于查询scn的,读取是安全的,因此直接把5作为结果返回给用户。完全违 背了数据库(块)的一致性读取。因此Oracle在直接路径读取之前,都会发生一个段一级的检查点来保证一致性的读取。通过10046很容易看到发生的段 级别的检查点。
PARSING IN CURSOR #4573489040 len=22 dep=0 uid=45 oct=3 lid=45 tim=1735265030575 hv=2763161912 ad='70000036058fd08' sqlid='cyzznbykb509s'
select count(*) from t
END OF STMT
PARSE #4573489040:c=60,e=101,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1842905362,tim=1735265030574
EXEC #4573489040:c=51,e=84,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1842905362,tim=1735265030719
WAIT #4573489040: nam='SQL*Net message to client' ela= 9 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1735265030759
WAIT #4573489040: nam='reliable message' ela= 89 channel context=504403173615444552 channel handle=504403173661108944 broadcast message=504403173662264424 obj#=-1 tim=1
735265031335
WAIT #4573489040: nam='enq: KO - fast object checkpoint' ela= 10064 name|mode=1263468550 2=65588 0=1 obj#=-1 tim=1735265041430
说明:
1)直接路径读取如果有必要,也会去构造CR块,不过这里的CR块是在PGA中构造的,而不是在buffer cache中构造的。
2)如果表上没有任何的脏数据,并不会触发段上的检查点,这一点也很容易用10046跟踪出来,因此如果你想通过10046跟踪到段检查点,需要保证这个表上在内存中有脏数据。
延迟块清除与直接路径读
由于直接路径读取是发生在进程的PGA中的,如果读取过程中,ORACLE发现一些块没有做块清除,会在PGA中进行延迟 块清除的操作,但是这个清除的操作并不会记录日志,且被清除过的块并不会被刷回到磁盘。正是由于延迟清除过的块不被写回到磁盘,因此如果有比较多的进程来 进行直接路径读取,就会导致各个进程反复的进行块清除的操作,一定程度上浪费了CPU资源。(我们下面的测试用到的 snap_my_stats包,可以采样两次会话的统计信息差值,来获取两次采样间的信息增量)
1)我们先看看传统路径扫描下,延迟块清除的情况
update t set object_id=1 where rownum<10000;
另开一个session对buffer_cache进行刷新。
SQL> commmit;
禁用direct path read
SQL> alter session set "_serial_direct_read"=false;
Session altered.
SQL> execute snap_my_stats.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL> execute snap_my_stats.end_snap
SQL> ---------------------------------
Session stats - 08-Sep 11:51:00
Interval:- 11 seconds
---------------------------------
Name Value
---- -----
redo size 9,764
cleanouts only - consistent read gets 135
immediate (CR) block cleanout applications 135
commit txn count during cleanout 135
cleanout - number of ktugct calls 135
PL/SQL procedure successfully completed.
可以看到,相关延迟块清除的工作,都有了相应的指标,而且清除过程中产生了redo。我们来看看第二次读取还会不会发生延迟块清除。
SQL> execute snap_my_stats.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL> execute snap_my_stats.end_snap
SQL> ---------------------------------
Session stats - 08-Sep 11:51:24
Interval:- 3 seconds
---------------------------------
Name Value
---- -----
DB time 343
non-idle wait count 5
consistent gets 140,109
consistent gets from cache 140,109
PL/SQL procedure successfully completed.
没有任何延迟块清除的统计信息了
采用传统的路径读取,延迟块清除只需要进行一次,后续如果再有会话读取,不需要再做任何有关块清除的工作。
2)直接路径扫描下延迟块清除的情况
准备工作略(update,flush buffer cache,commit)
SQL> alter session set "_serial_direct_read"=auto;
Session altered.
SQL> execute snap_my_stats.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL>execute snap_my_stats.end_snap
SQL> ---------------------------------
Session stats - 08-Sep 11:53:39
Interval:- 4 seconds
---------------------------------
Name Value
---- -----
cleanouts only - consistent read gets 135
immediate (CR) block cleanout applications 135
commit txn count during cleanout 135
cleanout - number of ktugct calls 135
PL/SQL procedure successfully completed.
第一次读取发生了延迟块清除。但是由于redo size 没发生任何变化,因此没有结果显示。
SQL> execute snap_my_stats.start_snap
PL/SQL procedure successfully completed.
SQL> select count(*) from t;
COUNT(*)
----------
10090944
SQL>execute snap_my_stats.end_snap
SQL> ---------------------------------
Session stats - 08-Sep 11:53:52
Interval:- 3 seconds
---------------------------------
Name Value
---- -----
cleanouts only - consistent read gets 135
immediate (CR) block cleanout applications 135
commit txn count during cleanout 135
cleanout - number of ktugct calls 135
PL/SQL procedure successfully completed.
第二次查询依然会进行延迟块清除,一定程度上多消耗了CPU时间。
参考至:
http://afatkulin.blogspot.com/2009/01/11g-adaptive-direct-path-reads-what-is.html
http://afatkulin.blogspot.com/2012/07/serial-direct-path-reads-in-11gr2-and.html
http://www.itpub.net/thread-1815281-1-1.html
http://blog.tanelpoder.com/2012/09/03/optimizer-statistics-driven-direct-path-read-decision-for-full-table-scans-_direct_read_decision_statistics_driven/
如有错误,欢迎指正
邮箱:czmcj@163.com
相关推荐
utility that moves data from flat files to a running instance of Oracle 9i using the Oracle Call Interface (OCI) Direct Path API.
TI DirectPath放大器系列,以TPA6130A2为代表,是针对手机和便携式播放器设计的专业音频解决方案。这款放大器创新性地采用了DirectPath技术,旨在优化低频性能,减小解决方案尺寸,并提高电源纹波抑制比(PSRR),以...
本文将深入探讨`.X`文件的结构,以及如何在Direct3D中解析和使用这些文件。 `.X`文件通常包含以下关键组成部分: 1. **骨骼数据**:这是骨骼动画的核心,由一系列相互连接的节点(或称为骨骼)构成,对应于3D模型...
通过阅读“深入理解Direct3D9.rar”中的文档,开发者可以深入了解Direct3D9的各个方面,从而更好地驾驭这个强大的图形API,创作出高质量的3D应用。每个HTML文件可能分别涵盖上述一个或多个主题,提供详细的技术解析...
#Core session logical reads ...direct path read direct path write #Network Traffic bytes sent via SQL*Net to client bytes received via SQL*Net from client SQL*Net roundtrips to/from client
**CEGUI 深入解析教程** CEGUI(Crazy Eddie's GUI System)是一个开源的图形用户界面(GUI)库,适用于多种游戏引擎和实时3D应用。它提供了丰富的组件和自定义能力,使得开发者可以轻松创建出具有高度互动性的用户...
TPA6130A2是DirectPath系列放大器之一,其性能超过了目前市场上的其它充电泵耳机驱动器,实现了109dB电源纹波抑制比(PSRR)与仅4mA静态电流,并率先提供了差动立体声输入与64级软件音量控制等功能。TPA6130A2的上述...
本主题将深入探讨C#中处理SVG `pathData`的方法,以及如何在屏幕上解析和绘制这些路径。 首先,`pathData`字符串是由多个字母指令和数字坐标组成的,如"M", "L", "H", "V", "C", "S", "Q", "T", "A"等,它们分别...
**CEGUI深入解析教程** CEGUI(C++ GUI系统)是一个开源的,跨平台的图形用户界面库,专为游戏开发和实时3D应用程序设计。本教程将带你深入理解CEGUI的核心概念,帮助你掌握其使用方法并有效地利用它来构建高效、...
《CEGUI深入解析 Crazy Eddie’s GUI》是一本专注于Crazy Eddie’s GUI System(简称CEGUI)的详尽指南。CEGUI是一个开源的、跨平台的图形用户界面(GUI)库,专为游戏开发和实时3D应用设计。本书旨在帮助开发者深入...
在Android系统中,直接I/O(Direct IO)是...它需要开发者深入理解JNI、Direct IO的工作原理,以及加密TF卡的特性。通过熟练运用这些技术,可以实现高效且安全的数据读写,尤其适用于对速度和隐私有高要求的应用场景。
通过阅读和理解这段代码,我们可以更深入地了解DIRECT算法的内部工作机制,包括如何划分超矩形、如何选择分割策略以及如何更新搜索空间等细节。 总的来说,DIRECT算法是一种强大的全局优化工具,对于解决那些难以用...
禁用和开启DirectDraw加速,Direct3D 加速,AGP纹理加速批处理 在使用本程序前,请先确认你已经安装最新的显卡驱动程序 使用说明: 解压缩,XP系统用户直接运行BAT文件,WIN7系统用户,请右键以管理员身份运行,否则...
Direct 3D是微软开发的一种低级图形应用程序接口(API),它是Windows操作系统中的一部分,用于...在PDG格式的书中,你可以期待找到详细的理论解析、实践教程和可能的疑难问题解答,帮助你在Direct3D的世界中游刃有余。
通过学习这些材料,你可以深入了解如何使用DirectDraw进行2D图形编程,以及如何利用其特性来优化应用程序的性能。同时,它也可能涵盖了如何在不同的Windows版本上部署和调试DirectDraw应用程序的技巧。
DirectX是微软开发的一套用于Windows操作系统的应用程序接口(API),它主要服务于多媒体和游戏开发,其中Direct...通过深入理解DirectDraw的基本原理和应用实例,开发者可以创建出更加丰富、生动的2D图形应用程序。
高资源消耗sql定位:消耗CPU较多的sql:消耗磁盘较多的sql:查找产生direct path read的SQL,查询当前等待事件,主要是direct path read
通过阅读这些笔记,开发者可以深入理解DirectUI的工作机制,学习如何在自己的项目中应用这项技术。 实习日记.docx可能是作者在实习期间使用DirectUI进行开发的记录,可能包含了在实践中遇到的问题、解决方案、心得...