2010-10-05

Oracle Optimizer

Oracle Optimizer의 원리 이해 및 SQL & 애플리케이션의 튜닝(하):

오라클의 튜닝 기법의 100% 활용
최세훈│한국오라클

지난 회에서는 튜닝에 들어가기 위해 먼저 Oracle Optimizer의 원리와 특징에 대해서 설명했다.
이번 회에서는 조인 메소드별 특징과 플랜 보는 법을 이해하고, 실제 오라클에서 제공하는 튜닝 기법들을 활용해 보도록 하자.

숲을 보는 튜닝
튜닝에는 정답이 없다. 즉 튜닝은 시스템의 특징이나 업무의 특징들을 정확히 이해하고, 그 상황에 맞게 문제의 원인을 확인하고, 문제의 원인을 해결하기 위한 최적의 튜닝 방법을 찾아야 한다는 것이다.
튜 닝의 기본 목표는 자원을 상황에 맞게 효율적으로 사용해서 원하는 결과값을 원하는 시간 내에 받아보는 것이다. 병렬 기능을 많이 사용한다고 해서 항상 좋은 결과가 나오는 것은 아니다. 또한 시스템의 자원은 한정되어 있다는 것을 항상 명심해야 한다. 하나의 애플리케이션이 한정된 시스템 자원을 병렬 기능을 사용해서 독점한다면, 다른 애플리케이션들은 상대적으로 피해를 보게 되는 것이다. 즉 튜닝은 하나의 애플리케이션을 위한 것이 아니라 모든 애플리케이션이 조화롭게 운영될 수 있도록 하여야 한다는것이다.
이런 입장에서 필자는 나무를 보지 말고 숲을 보라고 항상 강조한다. 즉 단위 SQL 문장의 플랜(plan) 튜닝도 중요하지만, 전체적인 조화를 이루는 SQL 문장의 유형 및 구조적인 문제 등이 더 중요하다는 것이다. 업무 시작 이후에 구조적인 문제를 해결하려면 상당한 인적, 시간적 자원을 소모해야 하지만, SQL 문장의 플랜적인 튜닝은 해당SQL 문장의 튜닝결과를 적용하는 것으로, SQL 문장의구조적, 유형적 튜닝에 비해 상대적으로 적은 비용이 들 것이다. 그래서 튜닝 작업을 이런 측면에서 바라보도록 항상 노력하여야 할 것이다.

조인 메소드별 특징
오라클의 조인 메소드는 Nested Loop Join(NLJ), Sort Merge Join(SMJ), Hash Join(HJ)의 3가지가 있다. 이들 3가지 조인 메소드로 여러 조인 타입 (Basic(natural) Join, Outer Join, Semi Join, Anti Join 등)을 지원하게 된다. Oracle Optimizer는 최적화 단계에서 이들 조인 메소드들 중 조인에 대한Selectivity와Cardinality의 계산에 의해 가장 효율적인 것을 선택하게된다. 단 RBO(Rule Base Optimizer)에서는 인위적인 힌트(USE_HASH)를 주지않고서는 Hash Join은 전혀 고려하지 않는다. 힌트를 준 것 자체가 이미 RBO가 아니라 CBO(Cost Base Optimizer)로 동작되는 것이다.
조인 을 확인할 때 조인 메소드 뿐만 아니라 조인 순서 또한 중요하다. 먼저 액세스 되는 쪽을 ‘드라이빙테이블(Driving Table) ’ 이라고 하며, 나중에 액세스되는 테이블을‘이너 테이블(Inner Table)’이라고 한다. Hash Join 에서는‘Build Table’과‘Probing Table’이라는 용어로 사용된다. SQL 문장에서 튜닝을 잘 하기 위해서는 조인 메소드별 특징을 정확히 이해하고 플랜을 통해 처리되는 과정을 그려볼 수 있어야 한다.


























Nested Loop Join(NLJ)
• NLJ는 순차적인 처리로Fetch의 운반단위(Array Size, Prefetch Size)마다 결과 로우(row)를리턴 받을 수 있다.
• 첫 번째 로우를 받는 시간은 빠르나, 전체 결과 로우를 받는 데까지 걸리는 시096 ORACLE KOREA MAGAZINE 간은 느리다. 즉 첫 번째 로우를 받을 준비가 되어 있는 단계까지를 실행시간으로 볼 때 실행시간은 빠르나 Fetch 시간은 느리다.
• NLJ는 메모리가 필요 없는 조인이다. 그러므로 추가적인 메모리 비용이 필요없다.
• NLJ는 드라이빙 테이블에서 많은 로우들이 필터링되어 이너 테이블로 찾아 들어가는 부분을 줄여야 하므로 드라이빙 순서가 중요하다.
• 이너 테이블은 드라이빙 테이블의 리턴되는 모든 로우들에 대해서 반복 실행하므로 액세스 효율이 좋아야 한다. 즉 대부분의 경우 이너 테이블은 인덱스가 있어야 한다. 또한 인덱스의 효율이 좋아야 한다. 이너 테이블이 작더라도 액세스 횟수가 많다면 인덱스가 있어야 한다. 인덱스의 효율이 좋지 않아 전체의 Index Range Scan과 같은 경우는 최악의 조건이다.
• NLJ는 주로 인덱스 위주의 싱글 블록 I/O의랜덤I/O 위주이므로OLTP에서 적은 데이타 범위 처리에 주로 사용된다. 즉 전체의 15% 이상의 경우는 Full Table Scan을 이용한 Sort Merge 또는 Hash Join을 이용한다.
• NLJ도 드라이빙 테이블이 Full Table Scan에 병렬로 처리되면 이너 테이블도 병렬로 종속적으로 처리된다.


























Sort Merge Join(SMJ)
• 전체 로우를 리턴 받는 시간이 빠르다. 즉 첫 번째 로우를 리턴 받을 준비까지의 시간은 느리지만, 준비가 된 상태에서의 Fetch 시간은 빠르다(메모리에서 리턴하므로). 이는 대상 로우들(Where 조건에 의해 필터된 로우들만 정렬)을 가지고 정렬 작업(모든 로우들을 조인 키로 정렬)을 하기 전까지는 어떠한 로우도 리턴할 수 없기 때문이다.
• NLJ와같이 드라이빙 테이블의 리턴되는 로우 수와 이너 테이블의 액세스 패턴에 의에 액세스 효율이 좌우되지 않으며, 조인 테이블 간에 자신의 처리범위로만 처리량을 결정하므로 독립적이다.
• 추가적인 정렬 메모리(SORT_AREA_SIZE) 비용이 필요하다. 메모리가 부족하면 TEMP 테이블스페이스에 정렬 중간단계(Sort Runs)를 기록하게 되므로 추가적인 디스크 I/O비용이 발생할 수 있다.
• 정렬 메모리에 위치하는 대상은 조인 키뿐만 아니라 Select List도 포함하므로 불필요한 Select List는 제거해야 한다.
• 정렬 작업의 CPU 사용에 대한 오버헤드가 있다. 그러므로 많은 로우들과 전체적으로 Select List의 사이즈의 합이 큰 테이블의 조인에는 문제가 있다. 즉 디스크 정렬을 피할 수가 없으며, 정렬에CPU 비용이 많이 든다.
• 디스크 정렬만 발생하지 않는다면 넓은 범위 처리에 유리하다.
• 디스크 정렬을 피할 수 없는 경우라면(Batch Job, Create index,...)
SORT_AREA_SIZE , SORT_MULTIBLOCK_READ_COUNT를SQL마다 세션 레벨에 할당해서 사용하도록 한다(WORKAREA_SIZE_POLICY가 Manual일 경우나 Oracle9i Database 이전 버전에서). 또한TEMP 테이블 스페이스의 Extent Size도 충분히 크게 주도록 한다.
ALTER SESSION SET SORT_AREA_SIZE= 104857600; ALTER SESSION SET SORT_AREA_RETAINED_SIZE= 104857600; (같이 준다) ALTER SESSION SET SORT_MULTIBLOCK_READ_COUNT=128; • 정렬 메모리의 크기는 (= Target rows×(total selected column’s bytes)×2) 이상 설정하되, PGA의 메모리 한계로 인해 테스트를 통해 PGA Memory Allocation Error가 발생하지 않는 범위 내에서 설정하도록 한다. 필요시 10032 Trace를 이용해 점검한다.
ALTER SESSION SET EVENTS ‘10032 TRACE NAME CONTEXT FOREVER’;



 
































































Hash Join(HJ)
• Hash Join은 두 개의 조인 테이블 중Small Rowset(Where 조건에 의해 필터링된 로우 수가 작은 테이블)을 가지고 HASH_AREA_SIZE에 지정된 메모리 내에 해시 테이블을 만든다.
• 해시 테이블을 만든 이후부터는NLJ의 장점인 순차적인 처리 형태이다. 그러므로NLJ과SMJ의 장점을 가지고 있다.
• Hash Join은 Basic Join( ‘=’)만 가능하다.
• NLJ와같이 드라이빙 테이블의 리턴되는 로우 수와 이너테이블의 액세스 패턴에 의에 액세스의 효율이 좌우되지 않으며, 조인 테이블 간에 자신의 처리 범위로만 처리량을 결정하므로 독립적이다.
• SMJ의 단점인 많은 로우들의 처리 또는 전체적으로 Select List의 사이즈의 합이 큰 테이블의 조인시 정렬 작업의 CPU 사용에 대한 오버헤드 및 디스크 정렬과 같은 문제점은 없다. 그러므로 최소한SMJ보다는 우수하다.
• 한 테이블은 작은 Rowset 사이즈(리턴되는 로우 수와 Select List 기준), 다른 한 테이블은 아주 큰 사이즈의 조인에 유리하다. 이러한 경우는 반드시 작은 사이즈를 가지고 해시 테이블을 만들어야 한다. 단, Hash Join은 순서가 매우 중요하다는 점에 주의하는데, 작은 Rowset으로 해시 테이블을 만들어야 하기 때문이다.
• 힌트를 잘못 주어서 Big Rowset이 리턴되는 테이블부터 드라이빙된다면(Build Table), HASH_AREA_SIZE의 메모리 부족으로 TEMP 디스크 I/O가 발생한다. 그러므로 힌트를 줄 경우 반드시 드라이빙 순서를 정확히 주어야 한다.
• 디스크 I/O를 피할 수 없는 경우라면, HASH_AREA_SIZE(default : =SORT_AREA_SIZE×2)를 SQL마다 세션 레벨에 할당해서 사용하도록 한다(WORKAREA_SIZE_POLICY가 Manual일 경우이거나 Oracle9i Database 이전 버전에서). 또한TEMP 테이블스페이스의 Extent Size도 충분히 크게 주도록 한다. HASH_MULTIBLOCK_IO_COUNT는 옵티마이저에게 자동 조정하도록 설정하지 않는다.
ALTER SESSION SET HASH_AREA_SIZE= 104857600; • 해시 메모리의 사이즈는 (= Small Table의 Target rows×(total selected column’s bytes)×1.5) 이상 설정하되, PGA의 메모리의 한계로 인해 테스트를 통해 PGA Memory Allocation Error가 발생하지 않는 범위 내에서 설정하도록 한다. 필요시 10104 Trace를 이용해 점검한다.
ALTER SESSION SET EVENTS ‘10104 TRACE NAME CONTEXT FOREVER’;
SQL 튜닝시 고려사항
SQL 튜닝시에 고려해야 할 점을 정리하면, 다음과 같다.
• 가능한 힌트는 사용하지 않는다. 힌트를 많이 구사한 애플리케이션들은 지난호에서 설명했던 것과 같이 기준(파라미터 및 통계정보)이 잘못 설정된 경우가 많다. 힌트는 최후에 어쩔 수 없는 경우에 사용하도록 한다.
- 1차적으로 플랜이 원하는 경우가 아닐 경우 통계정보 및 Init.ora의 파라미터 값들을 확인해 본다.
[USER|ALL|DBA]_TABLES,[USER|ALL|DBA]_INDEXES,[USER|ALL| DBA]_TAB_COLUMNS 등의 딕셔너리 정보 확인, 최종 분석 시간, 블록 수, 로우 수, 칼럼의 Distinct 값, 인덱스의 Clustering Factor, Sample Size 등을 확인하다. 이들 값들이 현실 데이타와 비슷한지 확인한다. 통계정보가 없거나 너무 오래됐거나 샘플링 사이즈가 너무 작은 경우, 현실 데이타와 다를 수 있다. 이러한 경우는 통계정보를 다시 생성한다.
- 칼럼에 대한 통계정보(히스토그램)는 안 돌리는 것을 원칙으로 한다. 그러나 편향된 데이타 분포도를 가지고 있다면 히스토그램을 운영한다. 또한 이들 칼럼에 대한 Where 절의 사용되는 값들은 바인드 변수를 사용하지 않도록 한다. 히스토그램을 사용하는 곳에는 상수(literal) 값을 사용하여야 플랜이 효과적으로 풀린다.
- 힌트를 지정할 경우는 가능한 타이트하게 주도록 한다. 그렇지 않을 경우 향후 플랜이 변경될 가능성이 많기 때문이다.
예> /*+ USE_NL(a b) */ ==> /*+ ORDERED USE_NL(a b) .... */ - 힌트는 힌트의 의미를 정확히 이해하고 합당한 힌트를 주도록 한다. 어설픈 힌트는 오히려 역효과가 발생되는 경우가 많다.

• 통계정보는 운영중에 직접 돌리지 않는다.
- 집중적인 운영시기에 통계정보 수집을 위한 실행은 Library Cache Contention을 유발하며, 관련 SQL 및 PL/SQL들을 Invalid시켜 성능저하 및 문제의 원인이 되기도 한다.
- 저녁시간의 한가한 시간을 이용해서 돌린다(특히 시스템의 집중 사용시기 등에 유의).

• WORKAREA_SIZE_POLICY=AUTO이면*_AREA_SIZE는 이용하지 않으며, 설정해봐야 의미가 없다. 즉 옵티마이저는 *_AREA_SIZE에 의해 플랜을 결정하지 않는다.

• 튜닝시 플랜적인 튜닝뿐만 아니라 구조적인 튜닝에도 집중한다.
- Execution이 높은 것은 과다한 Loop Query가 아닌지 검토한다. Loop Query의 보완, 최적화가 필요하다.
- 일회성(상수를 사용) 비공유 SQL, 특히 집중적으로 실행되는 Literal SQL은 바인드 변수 기법을 사용한다.
- 파싱(parsing)을 줄이는 방법으로 Java의‘Statement Cache’, PRO*C의 RELEASE_CURSOR=NO 등 프그래밍 언어의 효과적인 기법들을 사용한다.
- Array Processing 기능을 사용한다. 기본적으로 거의 대부분의 DB 접속 방식에서 이들 기법들을 제공하고 있으며, 코딩상의 특별한 처리 없이 PREFETCH 기능이 이와 같은 기능이며, 애플리케이션 개발시 특별한 구현 작업 없이 옵션 설정만으로 가능하다(ODBC, JDBC, OO4O, ADO, PRO*C 등).
- PL/SQL의 Bulk Binding/Bulk Collecting 기능을 이용한다.
- Aggregate Function 등 향상되고 효과적인 여러 질의 기능을 활용한다.

• 튜닝시 플랜은 상수로 테스트하지만, 실제로 바인드 변수로 운영되는 경우 플랜이 다를 수 있다. 프로그램에 바인드 변수로 되어 있다면 바인드 변수로 플랜을 확인해 봐야 한다.

• 기타 다음 사항도 고려한다.
- Hash Join을 사용할 경우 드라이빙 순서, Rowset을 고려하여 사용한다.
- SQL 문장에서 반드시 필요한 칼럼만 선택한다. 불필요한 칼럼들은 정렬, 해시 작업에서 메모리에 로딩해야 하므로 TEMP 디스크 I/O의 원인이 되기도 한다.
- Chaining % 비율을 항상 검토하고 Row Chaining 비율이 높은 테이블에 대해서는 칼럼의 데이타 타입 조정 및 블록의 PCTFREE 등을 늘리도록 한다. 테이블의 구조적인 문제 또는 업무적인 형태를 고려하여 Reorg를 하도록 한다(CTAS, MOVE, Exp/Imp 등 이용).

• 평균 로우 길이와 블록당 로우 수도 항상 주의 깊게 관찰하여 문제점이 없는지 검토한다 (통계정보이용 DBA_TABLES.NUM_ROWS/DBA_TABLES.BLOCKS). 블록당 로우가 적은 경우는DELETE가 많이 된 경우이므로, Full Table Scan이 자주 발생된다면 Reorg 대상이 될 수 있다. 그러나RAC 환경에서는 블록 경합을 줄이기 위해 인위적으로PCTFREE를 키워 블록당 로우 수를 적게 가져가는 경우도 있다.

• Hash Join과 Sort Merge Join시TEMP쪽에 I/O가 발생하지 않도록 한다.

• PRO*C 애플리케이션일 경우, 바인드 변수의 사용여부, RELEASE_CURSOR=NO, PREFETCH=1000(batch), PREFETCH=100(OLTP)를 권장한다.

Execution Plan 보기
Execution Plan이란 옵티마이저가 질의 최적화 단계에서RBO 또는CBO에 의해 결정해낸 최적의 액세스 경로 정보를 가지고QEP Generator가 만들어낸 실행 계획이다. 이Execution Plan은SQL 문장이 실행될 때 필요한 모든 정보를 포함하고 있다.
• 액세스 경로 : 어떠한 방법으로 데이타에 접근할 것인가? (Index Scan, Index Fast Full Scan, Full Table Scan 등)
• 조인 메소드 : 어떤 조인 메소드를 사용할 것인가?
• 조인 순서 : 어떠한 조인의 순서로 풀릴 것인가
?
다음과 같은 Execution Plan을 가정하자.
















플랜에서 나오는 각 라인을‘로우 소스(Row Source)’라고 한다. 플랜을 보면서 처리 순서를 판단하는 것은 간단하다. 플랜은 트리 형태로 되어 있으며, 자신보다 하위 레벨이 있으면 하위 레벨부터, 같은 레벨이라면 위(상)의 로우소스부터 실행 된다.
위 플랜의‘Optimizer=CHOOSE’에서알수있듯이해당SQL 문장은 옵티마이저 모드가 CHOOSE에서 플랜이 만들어진 것이다. 또한 플랜에서 ‘Cost=’의 항목이 나오면CBO로 풀렸다는 것이다. RBO인지 CBO인지의 판단은 옵티마이저 모드의 항목으로 판단하는 것이 아니라 ‘Cost=’로 판단한다는 것에 주의하자.
위 플랜에서 2개의 테이블 DEPT와 EMP 테이블 각각의 액세스 경로를 확인할 수 있다. 모두 인덱스를 사용하고 있는 것이다. 또한 조인메소드로는 Nested Loop Join이 사용되었다. 조인 순서는 자신보다 하위 레벨이 있으면 하위 레벨부터, 같은 레벨이라면 위의 로우 소스부터 실행된다는 법칙을 적용해보면, ID를기준으로4 -> 3 -> 5 -> 2 -> 1 -> 0의 순서로 처리 된다. 단 조인메소드가 Nested Loop이기 때문에 3에서 리턴되는 로우 수만큼 다음 단계가 반복된다. 그러므로 조인 순서는 DEPT -> EMP 순으로 Nested Loop로 처리될 것 이라는 것을 알 수 있다.
또한‘Card=5’는Computed Cardinality를나타내며, 몇 건의 로우가 리턴될 것인지를 CBO가 통계정보를 이용해서 계산해낸 값이다.
‘Bytes=250’은 리턴 될 로우들의 바이트를 나타내므로 5 로우에 250바이트 정도의 리턴 로우가 발생할 것이라는 것을 예측할 수 있다. 통계 정보만 정확하다면 이들 값도 상당히 정확하다고 보면 된다.
Execution Plan을제대로보기위해서는,

• 각 데이타베이스 사용자마다 PLAN_TABLE이 있어야 하는데, PLAN_TABLE은 오라클 버전마다 다르다. 해당 오라클 버전의 $ORACLE_HOME/rdbms/admin/utlxplan.sql을 실행하면 만들어진다.
• SQL을 실행하지 않고 Trace만 보는 방법도 있다.
• EXPLAIN PLAN’<리 스 트 1>, SQL*Plus의‘ SET AUTOTRACE TRACEONLY EXPLAIN’<리스트 2>.
• 플랜을PLAN_TABLE에서 확인할 수도 있다.
Oracle8i Database 이전까진 Plan_Table에서 직접 선택하고, Oracle8i Database 이상부터는 Plan_Table에서 직접 선택하거나 $ORACLE_HOME/rdbms/admin 위치에서 utxpls.sql(Serial Plan) 또는 utlxplp.sql(Parallel Plan) 스크립트를 실행하면 된다. Oracle9i Database 이전에서는 utxpls.sql, utlxplp.sql 외에‘select * from table(dbms_xplan.display);’






























































































































































































Cached Execution Plan(V$SQL_PLAN)
Explain Plan으로 보는 플랜과 실제 실행시 플랜이 다를 수 있다. 이는 Explain Plan은단지SQL 문장에 대한 구조적인 분석하에 예상 플랜을 만들어내기 때문이다. 예를 들어, ‘select * from emp where empno = :B1’의 SQL 문장을 실행한다고 생각해 보자.
Empno가 인덱스가 설정되어 있고 Character 타입으로 되어 있으며, 인덱스를 이용하는 것이 효과적이라고 가정하면 Explain plan은 Empno의 인덱스를 이용해서 풀릴 것이다. 그러나 실제 실행시 바인드 변수인 ‘:B1’에Character 타입이 아니라 Number 타입으로 바인드 되었다면 인덱스를 이용할 수 없는 것이다. 또한 Oracle9i Database의 Bind Peeking과 같은 기능은 처음 바인딩되는 상수에 의해 플랜을 결정하는데, 이 방식에 의해서도 그러한 상황이 있을 수 있다.
이와 같이 Explain Plan을 보는 것과 실제 예측 실행시간이 너무 차이가 난다면 Runtime Plan을 확인해 볼 필요가 있다. Oracle9i Database부터 V$SQL_PLAN의 성능뷰를 제공하며, 현재 캐쉬화 되어 있는 SQL 문장들에 대한 Runtime Plan을 확인해 볼 수 있다. V$SQL_PLAN은PLAN_TABLE과 칼럼 항목이 거의 같다.

SELECT hash_value, (select sql_text from v$sql s where s.hash_value = p.hash_value and
s.address = p.address and rownum <= 1), child_number,ID ,PARENT_ID , LPAD( ‘
‘,2*(depth))||OPERATION||DECODE(OTHER_TAG,NULL,’’,’*’)|| DECODE(OPTIONS,NULL,’’,’
( ‘||OPTIONS||’)’)||DECODE(OBJECT_NAME,NULL,’’,’OF ‘’’||OBJECT_NAME||’’’’)||
DECODE(OBJECT#,NULL,’’,’(Obj#’||TO_CHAR(OBJECT#)||’)’)||DECODE(ID,0,DECODE(OPTIMIZER,
NULL,’’,’Optimizer=’||OPTIMIZER))||DECODE(COST,NULL,’’,’
(Cost=’||COST||DECODE(CARDINALITY,NULL,’’,’Card=’||CARDINALITY)||DECODE(BYTES,NULL,’’,’
Bytes=’||BYTES)||’)’) SQLPLAN,OBJECT_NODE, PARTITION_START ,PARTITION_STOP,
PARTITION_ID, CPU_COST, IO_COST, TEMP_SPACE, DISTRIBUTION, OTHER
ACCESS_PREDICATES , FILTER_PREDICATES FROM v$sql_plan p
START WITH ID=0 and hash_value = [XXXXXXXXXX]
CONNECT BY PRIOR ID=PARENT_ID AND
PRIOR hash_value=hash_value AND
PRIOR child_number=child_number
ORDER BY hash_value,child_number,ID,POSITION

SQL_TRACE와TKPROF를 이용한 SQL 튜닝

SQL_TRACE 또는 10046 Trace Enable/Disable

SQL_TRACE는 애플리케이션이 SQL 문장들을 처리하는 과정을 Trace로 남기게 하는 기능이다. 10046 Trace 기능은SQL_TRACE의 기능에 추가적인 정보를 기록한다. 레벨1은SQL_TRACE 기능과같으며, 레벨4는바인드 변수 정보, 레벨8은Wait Event 정보, 레벨12는 바인드 변수 정보와 Wait Event 정보를 같이 보여준다.
주의할 점은 Trace를 On 했으면 반드시 모니터링 후 Off 해야 한다는 것이다. 그렇지않을경우Disk Full이 발생할 수 있으므로 반드시 주의해야 한다. Trace는init.ora의 user_dump_dest에서 지정된 곳에 생성된다.

• 인스턴스 레벨 : init.ora 파라미터 이용
sql_trace = {TRUE | FALSE} 또는 event = “10046 trace name context forever, level {1|4|8|12}” • 세션 레벨 : SQL*Plus 또는 애플리케이션 루틴 내

ALTER SESSION SET SQL_TRACE = {True|False};
또는10046 Trace On
alter session set events ‘10046 trace name context forever, level {1|4|8|12}’;
10046 Trace Off
alter session set events ‘10046 trace name context off’;
또는
EXECUTE dbms_session.set_sql_trace({True|False});
또는
EXECUTE dbms_system.set_sql_trace_in_session(session_id, serial_id, {True|False});

Execution Plan 보기(SQL_TRACE,10046 Trace와 TKPROF) 실행 예(Oracle9i Database)
Oracle9i Database Release 2(9.2.x)부터는 튜닝 대상이 어느 곳인지(플랜상의 스텝) 판단하기 쉽게 획기적으로 개선되어, 초보자도 튜닝 대상을 쉽게 찾을 수 있다. 또한 사용자가 SQL 문장을 실행해서 결과 값을 받는 서비스 타임은‘DB 실행시간 + 대기시간’이다. Oracle9i Database부터는 SQL TRACE의 레벨에 따라 Wait 정보의 요약 정보도 같이 보여주므로 어느 곳에 병목 현상이 있는지 판단하기 쉬워졌다. 다음은Oracle9i Database Release2(9.2.x)부터개선된사항이다<리스트3>.

• 10046 Trace 레벨에 따라 Wait(레벨 8, 레벨12일경우) 정보도 표시. 각로우소스(플랜상의 스텝)마다 Statistics 표시
• Oracle9i Database에서는 time=xxxxxxxxxx 정보가 1/1000000초 단위로 나타난다. Oracle8i Database까지는 1/100초였다.
• Runtime Plan & TKPROF 실행시 플랜 주의. TKPROF …. EXPLAIN=xxxx/yyyy일 경우 플랜이 2개(Runtime Plan & Tkprof 실행 시점의 플랜)



















































































































































































































TKPROF 아웃풋의 로우 값의 버전별 변화
TKPROF의아웃풋형태가Oracle8i Database 이전까지는테이블 또는 인덱스를 찾아 들어간 로우수를 나타내며, Oracle8i Database서 부터 로우값은 필터링되어 리턴된 로우 수를 나타낸다. TKPROF 아웃풋에 로우 값이 0으로 나오는 경우는 해당 SQL 문장의 커서가 종료되기 전에 Trace가 종료되었거나 끊긴 경우이다. Runtime Plan은 커서가 종료되는 시점에 기록되므로 이 값이 0으로 나올 수 있다.











































Oracle Database 10g의 튜닝 관련 신기능
Oracle Database 10g에서 튜닝 기능은 더욱 개선, 강화 되었다.

• 자동 성능 진단과 튜닝
Oracle Database 10g부터는 자가관리(self-management) 기능이 강화되었으며 , Automatic Statistics Collection, Automatic Database Diagnostic Monitoring(ADDM), Automatic SQL 튜닝과 같은 기능을 튜닝에 이용할 수 있다. Automatic Workload Repository(AWR)는셀프튜닝과 문제진단을 목적으로 성능 정보를 수집하고 처리하고 유지한다.
Automatic Database Diagnostic Monitor(ADDM)는AWR에 수집된 정보를 주기적으로 분석하고 오라클 시스템에 대한 문제의 원인을 진단하고 권장사항을 제공한다.
Oracle SQL Tuning Advisor는 SQL 문장의 최적화를 위해 빠르고 효과적인 방법을 제공한다. 내부적으로DBMS_SQLTUNE 패키지를 제공하며, 사람이 직접 하던 튜닝을 이제는 Oracle SQL Tuning Advisor의 기능을 이용해 문제의 원인을 상세하게 찾아내고 개선안을 얻을 수 있으며, 개선안을 수용하면 같은SQL 문장이 실행되었을 경우 튜닝된 결과로 플랜이 처리된다.

• Application End to End Tracing
Application End to End Tracing 기능은 클라이언트 식별자(Login ID), 서비스명(Application Group), 모듈명 또는 액션명으로 시스템 자원을 과다하게 사용하는 SQL 문장과 같은 워크로드의 원인을 찾을 수 있도록 해주는 유용한 기능이다. 즉 멀티티어 환경에서의 성능 디버깅을 쉽게 할 수 있는 기능이다.

• trcsess 유틸리티
trcsess는 커맨드라인 유틸리티로, 특정 검색조건에 해당하는 내용을 원하는여러Trace 파일에서 통합해서 한 파일로 만들어 준다. AP 서버를 두고 있는 분산 트랜잭션에서 여러AP 서버의 Trace에 분산되어 있는 Trace 정보에서 원하는 검색조건인 클라이언트 식별자, 서비스명, 모듈명 또는 액션명 등으로 찾아볼 수 있다. Application End to End Tracing의 기능에 의해 여러 파일에 흩어져 있는 Trace 내용을 모으는 데 유용하다.

• Automatic Optimizer Statistics Collection
각 오브젝트들에 대한 옵티마이저 통계정보를 자동으로 수집한다. 통계정보가 맞지 않거나 없는 경우에 자동으로 통계정보를 수집할 수 있다. DBA는 어떤 오브젝트에 대해서 통계정보를 실행해야 되는지, 어떤 통계정보가 맞지 않는지에 대해서 신경을 쓰지 않아도 되며, 직접 실행할 필요도 없다. 옵티마이저 통계정보는 GATHER_STATS_JOB로 자동으로 수집할 수 있으며, DB를 생성하거나 업그레이드할 때 자동으로 설정된다(디폴트). 이 기능은 Missing Statistics(통계정보가 없음) 또는 Stale Statistics(대량의 데이타
로딩 등에 의해 로우들이 10% 이상 변경된 경우)인 경우에 이들 오브젝트들을 관리하고 이들 오브젝트에 대해서 자동으로 수집한다. 수집 시기도 시스템 자원이 한가한 새벽시간에 운영된다.
지금까지 2회에 걸쳐 Oracle Optimizer의 원리 이해를 기반으로SQL과 애플리케이션의 튜닝 방법에 대해서 설명하였다. 애플리케이션 튜닝 부분은 자세히 다루지는 않았지만, 이번 기회에 Oracle Optimizer의 원리를 이해하고, SQL 튜닝기법을 활용하여 시스템의 안정적인 개발 및 운영에 도움이 되었으면 하는 바람이다.

Oracle Kill Session

http://cafe.naver.com/sybaseealab.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=408

http://blog.naver.com/bluekisunny?Redirect=Log&logNo=120045145287

2010-10-04

오라클 캐릭터셋트 변경

select * from nls_database_parameters where parameter = 'NLS_CHARACTERSET';
select * from props$ where name='NLS_CHARACTERSET';

sqlplus '/as sysdba';

shutdown immediate;
startup mount;
alter system enable restricted session;
alter system set job_queue_processes=0;
alter system set aq_tm_processes=0;
alter database open;
alter database character set internal_use KO16MSWIN949;
shutdown immediate;
startup

2010-08-13

2010년 중등부 수련회에서...


적은 숫자였지만 행복한 시간이었다..
Posted by Picasa

2010년 중등부 수련회에서..

2010년 중등부 수련회에서 찍은 사진 한컷...
^^ 사실 내가 찍은 것은 아니고..

난 이 시간 아이들과 한바탕 서바이벌 게임을 즐기고(?) 있었다.
즐긴것도 아닌...

흐린날씨 그리고 더운 날씨 속에서 고글에 습기가 차 앞이 안보이는 환경에서 서바이벌 게임을 하려니 정말 곤역이었다.

앞으론 그 게임.. 못할 것 같다. ㅠㅠ
Posted by Picasa

2009-08-22

개구장이들



언제나 ...개구장이들~~
Posted by Picasa

비온뒤 맑은 날씨가 좋아서..

약간 흐린날씨...
그렇지만 기분좋은 날씨다.
조금 있으니 더욱 좋아지는 날씨.
이번엔 생각지도 않게 해까지 비치기 시작한다.
놀기를 너무나 좋아하는 아이들과 함께 집주변 산책길에 오른다.
Posted by Picasa

2009-03-05

[개발: Delphi] Grid 마우스 휠 사용..(질/답)

unit Fi233P;
..
..
private
..
procedure MouseWheelHandler(var Message:TMessage ); override;
public

end;

var
Fi233F: TFi233F;
implementation

{$R *.dfm}

procedure Fi233P.MouseWheelHandler( var Message:TMessage );
begin
if not ( Message.msg = WM_MOUSEWHEEL ) then Exit;
if not ( ActiveControl is TDBgrid ) then Exit;
if ( Message.wParam > 0 ) then Keybd_Event( VK_UP, VK_UP, 0,0 );
if ( Message.wParam < 0 ) then Keybd_Event( VK_DOWN,VK_DOWN,0,0 );
end;

위처럼 하면 해당폼의 그리드를마우스휠로 위 아래로 움직일 수 있습니다.
문제는 모든 폼에 다 위 구문을 써 주어야 한다는 겁니다.뭐..복사..붙여넣기 하면 됩니다만..

저걸 메인폼(기타 다른폼..?)에 한번만 기록해 놓고 각 폼에서 적용 받을 수 있나요?

========> 답변 ------------------
Application.OnMessage 에 이벤트 핸들러 걸어서..
거기서 하면 됩니다.

var aControl: TWinControl;
begin
if Msg.message = WM_MouseWheel then begin
aControl := FindControl(Msg.hWnd);
if (aControl is TDBGrid) then begin
if (Msg.wParam > 0) then Keybd_Event(VK_UP, VK_UP, 0,0);
if (Msg.wParam < 0) then Keybd_Event(VK_DOWN,VK_DOWN,0,0);
(aControl as TDBGrid).Invalidate; //그리드에 ▶ 표시를 없앤다..
end;
end;

-- 델마당 ---

[개발: Delphi] Build with runtime package?

Build with runtime package 란...

Delphi에서 Package에서
Dynamic Library(Dll)은 *.bpl 이라는 확장자를 가지고
Static-Library는 **.lib 가집니다.

Delphi7에서 VCL은 vcl70.bpl 이 됩니다.

그런데 Build with runtime package를 켜두지 않으면
실행파일 ***.exe에 vcl70.lib 라는 static 파일이 같이 묶여서
배포할때 vcl70.bpl을 같이 배포하지 않아도 되게 되죠
하지만 Build with runtime package를 켜두면 vcl70.bpl은

exe가 loading될때 LoadLibrary로 로드 됩니다.
이경우 vcl70.bpl도 같이 배포해야죠

그런데 Build with runtime packag를 꺼두면
exe에서도 vcl을 사용하고 dll에서도 vcl을 사용하게 되면
vcl이 두개 load되게 됩니다.

꼭 vcl이 아니라 프로그램에서 사용하는 Package는 모두 마찬가지죠

델파이는 기본옵션이 Build with runtime package가 꺼져잇는데..
개인적으로 Build with runtime packag를 켜서 컴파일하길 권장합니다.
배포에 좀 신경써야 하지만 exe(또는 dll) 크기도 작아지고
package중복문제도 없어지고...

-- 델마당에서 퍼옴 ---

2009-02-17

[개발: Delphi] Tips

http://wall.riscom.net/books/delphi/uddf/PAGES/

[개발: Delphi] Form관련 팁


Forms

Delphi Applications without Forms?

From: bpeck@prairienet.org (Bob Peck)

You bet! First, select File|New Project and choose "CRT Application" from the Browse Gallery dialog. This will provide you with a project that is still a Windows program, but WriteLn, ReadLn will be allowed in a Window but work like they did in DOS. If you wish, you can remove the WinCrt unit from the uses statement (if no user input/output is required, but is nice for debugging).

I've done this before just to see how small an app can be and I've been able to create a simple EXE (it just beeps) that is only 3200 bytes or so in size! Try to do that in C++ these days!

BTW, these "formless" apps are still Windows applications, so they can still call the Windows API routines. You'll just need to add WinProcs, WinTypes to your uses clause. You'll probably also want to add SysUtils and any other unit you find yourself needing.

Showing own logo on start-up

From: "Mark R. Holbrook"

It's pretty simple.

Create a form and put the logo on it using a Timage component. My example below assumes you have created a logo form called "logoform" Go to your project options and set the form to NOT be autocreated.

Then in your PROJECT.DPR file just after the begin statement do something like the following:


   logoform := TLogoform.Create(nil);
logoform.Show; { NOTE! show! NOT showmodal }

.
. { Do other app startup stuff here like open databases etc... }
.

. { Just after the block of code that creates all your forms and
before the Application.Run statement do: }

logoform.Hide;
logoform.Release;

This will display your logo form until you actually start the app running.

Moving a form without a caption bar

From: mger@sbox.tu-graz.ac.at (Matthias Gerstgrasser)

The following is from DKBS Helpfile (Delphi Knowledge Base System), they state, that this is one of Borland's TI's:

Q: How can I make a form move by clicking and dragging in the client area instead of on the caption bar?

A: The easiest way to do this is to "fool" Windows into thinking that you're actually clicking on the caption bar of a form. Do this by handling the wm_NCHitTest windows message...


type
TForm1 = class(TForm)
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;
end;

var
Form1: TForm1;

implementation
{$R *.DFM}

procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
inherited; { call the inherited message handler }
if M.Result = htClient then { is the click in the client area? }
M.Result := htCaption; { if so, make Windows think it's }
{ on the caption bar. }
end;

Preventing the user from resizing my window vertically

From: Bill Dekleris

You must trap WM_GETMINMAXINFO message:

in your form's class declaration put this :


procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;

and in the implementation section :


procedure TMyForm.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
begin
{ ---------------------------------------------}
{ Put your numbers in place of }
{ MIN_WIDTH, MIN_HEIGHT, MAX_WIDTH, MAX_HEIGHT }
{ }
{ To allow only horizontal sizing, put }
{ form's 'Height' property in place of MIN_HEIGHT, MAX_HEIGHT }
{ ---------------------------------------------}
Msg.MinMaxInfo^.ptMinTrackSize := Point(MIN_WIDTH, MIN_HEIGHT);
Msg.MinMaxInfo^.ptMaxTrackSize := Point(MAX_WIDTH, MAX_HEIGHT);
inherited
end;

It should work fine.

Hack: Want VCL controls in a form's title bar caption area?

From: "James D. Rofkar"

Here's the trick:

Treat your controls like they belong in a separate modeless dialog that just so happens to track the movement and resizing of your main form. In addition, it always appear over the main form's caption area.

This said, here's a simple hack that involves 2 forms and a drop-down listbox. After running this program, the drop-down listbox will appear in the Main form's caption area. Two key issues are: 1) trapping the Main form's WM_MOVE message; and 2) returning focus back to the Main form after users press any focus-grabbing controls (like a TComboBox, TButton, etc.)

[FYI, I'm using 32-bit Delphi 2.0 Developer under Win95 -- even though this technique should work for all versions of Delphi]

Here's the source for the Main form:


   unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
procedure FormResize(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormHide(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure WMMove(var Msg: TWMMove); message WM_MOVE;
end;

var
Form1: TForm1;

implementation

uses Unit2;

{$R *.DFM}

procedure TForm1.FormResize(Sender: TObject);
begin
with Form2 do
begin
{Replace my magic numbers with real SystemMetrics info}
Width := Form1.Width - 120;
Top := Form1.Top + GetSystemMetrics(SM_CYFRAME);
Left := ((Form1.Left + Form1.Width) - Width) - 60;
end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
Form2.Show;
end;

procedure TForm1.FormHide(Sender: TObject);
begin
Form2.Hide;
end;

procedure TForm1.WMMove(var Msg: TWMMove);
begin
inherited;
if (Visible) then FormResize(Self);
end;

end.

Here's the source for the pseudo-caption area form. This is the form that contains the VCL controls you wish to place in the Main form's caption area. Essentially, it's a modeless dialog with the following properties:


   Caption='' {NULL string}
Height={height of caption area}
Width={width of all controls in form}
BorderIcons=[] {none}
BorderStyle=bsNone
FormStyle=fsStayOnTop

Anyhow, here's the source for Form2:


   unit Unit2;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm2 = class(TForm)
ComboBox1: TComboBox;
procedure FormCreate(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
procedure FormResize(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

uses Unit1;

{$R *.DFM}

procedure TForm2.FormCreate(Sender: TObject);
begin
Height := ComboBox1.Height - 1;
Width := ComboBox1.Width - 1;
end;

procedure TForm2.ComboBox1Change(Sender: TObject);
begin
Form1.SetFocus;
end;

procedure TForm2.FormResize(Sender: TObject);
begin
ComboBox1.Width := Width;
end;

end.

The project file (.DPR) is fairly straightforward:


   program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.Run;
end.

That's it!

Although some Delphi book authors state:

"You can't place a Delphi component on the title bar, so there's literally no way to put a button there."

you can at least "fake" the illusion...

Storing TForm and/or its properties in a BLOB

From: Oliver.Bollmann@t-online.de (Oliver Bollmann)

Hallo, here are examples you need, I hope:


procedure SaveToField(FField:TBlobField;Form:TComponent);
var
Stream: TBlobStream;
FormName: string;
begin
FormName := Copy(Form.ClassName, 2, 99);
Stream := TBlobStream.Create(FField, bmWrite);
try
Stream.WriteComponentRes(FormName, Form);
finally
Stream.Free;
end;
end;

procedure LoadFromField(FField:TBlobField;Form:TComponent);
var
Stream: TBlobStream;
I: integer;
begin
try
Stream := TBlobStream.Create(FField, bmRead);
try
{delete all components}
for I := Form.ComponentCount - 1 downto 0 do
Form.Components[I].Free;
Stream.ReadComponentRes(Form);
finally
Stream.Free;
end;
except
on EFOpenError do {nothing};
end;
end;

Removing icon on taskbar

From: AVONTURE Christophe


 ShowWindow (Application.Handle, SW_HIDE);

How can I hide the form caption bar??

From: "James D. Rofkar"

First, override the "CreateParams" method of your Form, by declaring this in either your Form's protected or public section:


   procedure CreateParams(var Params: TCreateParams); override;

Then, in the actual CreateParams() method, specify something like this:


   procedure TForm1.Createparams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
Style := (Style or WS_POPUP) and (not WS_DLGFRAME);
end;

Hopefully, you'll provide some UI mechanism for moving and closing the window.

Floating toolbar - here's some code to do it

From: ao@atlas.sto.foa.se (Anders Ohlsson)

Someone asked for some code to make a form with no title bar moveable, kind of like a floating toolbar, for example FreeDock. Actually, for some of the stuff in here I spied on the FreeDock sources...

This requires the use of some WinAPI functions. All WinAPI functions are however available at a touch of a key (F1 - OnLine Help)...

Here's some code that does this (about 100 lines)...

To make this work like intended:

OR start a new project, make the form's borderstyle bsNone, add a panel, set the border style of the panel to bsSingle, add another panel with some caption, add a button that says 'toggle title bar', cut out the below code and insert it were it should be, enable the panel's three event handlers (MouseDown, MouseMove, MouseUp), enable the button's event handler (Click). Hope I didn't forget anything... ;-) It's done faster in Delphi than it's written here... ;-)


unit Unit1;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
Button1: TButton;
procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Panel1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
OldX,
OldY,
OldLeft,
OldTop : Integer;
ScreenDC : HDC;
MoveRect : TRect;
Moving : Boolean;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then begin
SetCapture(Panel1.Handle);
ScreenDC := GetDC(0);
OldX := X;
OldY := Y;
OldLeft := X;
OldTop := Y;
MoveRect := BoundsRect;
DrawFocusRect(ScreenDC,MoveRect);
Moving := True;
end;
end;

procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if Moving then begin
DrawFocusRect(ScreenDC,MoveRect);
OldX := X;
OldY := Y;
MoveRect := Rect(Left+OldX-OldLeft,Top+OldY-OldTop,
Left+Width+OldX-OldLeft,Top+Height+OldY-OldTop);
DrawFocusRect(ScreenDC,MoveRect);
end;
end;

procedure TForm1.Panel1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then begin
ReleaseCapture;
DrawFocusRect(ScreenDC,MoveRect);
Left := Left+X-OldLeft;
Top := Top+Y-OldTop;
ReleaseDC(0,ScreenDC);
Moving := False;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
TitleHeight,
BorderWidth,
BorderHeight : Integer;
begin
TitleHeight := GetSystemMetrics(SM_CYCAPTION);
BorderWidth := GetSystemMetrics(SM_CXBORDER)+GetSystemMetrics(SM_CXFRAME)-1;
BorderHeight := GetSystemMetrics(SM_CYBORDER)+GetSystemMetrics(SM_CYFRAME)-2;
if BorderStyle = bsNone then begin
BorderStyle := bsSizeable;
Top := Top-TitleHeight-BorderHeight;
Height := Height+TitleHeight+2*BorderHeight;
Left := Left-BorderWidth;
Width := Width+2*BorderWidth;
end
else begin
BorderStyle := bsNone;
Top := Top+TitleHeight+BorderHeight;
Height := Height-TitleHeight-2*BorderHeight;
Left := Left+BorderWidth;
Width := Width-2*BorderWidth;
end;
end;

end.

Comments

From: Steve Teixeira

I have one comment on the FloatWin sample, though: it's *much* more complicated than it needs to be. All you have to do is handle Windows' wm_NCHitTest message. Here is some code I wrote for a Borland Tech Info document that does the same thing.
unit Dragmain;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
inherited; { call the inherited message handler }
if M.Result = htClient then { is the click in the client area? }
M.Result := htCaption; { if so, make Windows think it's }
{ on the caption bar. }
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Close;
end;

end.

Programming for different resolutions in Delphi 2.0

You need to download:

Ti2861 - Form display with different screen resolutions.

from the Delphi Technical Support area of our web site at www.borland.com.

Cannot properly minimize a form on startup

From: abeldup@unison.co.za (Abel du Plessis)

I need to start my form minimized, unfortunetly it doesn't work. When I set the WindowState property of the main form
to wsMinimized and run it, the form minimizes onto Win95 desktop instead of the taskbar how it properly should.

Does anyone know how to fix this bug?
There was an article in The Delphi Magazine, Issue 19, March 1997 - the Delphi Clinic section which explained the problem.
Here is my adaptation of the fix:
unit Foobar;

interface

type
TfrmFoobar = class(TForm);
procedure DoRestore(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

implementation

procedure TfrmUVChannel.FormCreate(Sender: TObject);
begin
//Assign a temporary event handler for when the app gets restored
Application.OnRestore := DoRestore;
Application.Minimize;
end;

procedure TfrmFoobar.DoRestore(Sender: TObject);
begin
Application.ShowMainForm := True;
//Restore the application
Perform(wm_SysCommand, sc_Restore, 0);
//Ensure all components draw properly
Show;
//Disconnect this event handler so it will not be called again
Application.OnRestore := nil;
end;

initialization
//Hide the minimized main form for now
Application.ShowMainForm := False;

end.

How do I know a Form is 'ready' resizing?

From: rkroman@pacbell.net

The methods you might be concerned with are:


{Trap the GetMinMaxInfo message and set minimum window size}
{ using declared constants }
procedure TForm1.WMGETMINMAXINFO( var message: TMessage );
var
mStruct: PMinMaxInfo;
begin
mStruct := PMinMaxInfo(message.lParam);
mStruct.ptMinTrackSize.x := HORIZONTALSIZE;
mStruct.ptMinTrackSize.y := VERTICALSIZE;

message.Result := 0;
end;

Preventing a From from Resizing

Taken from Borland tech info articles

2958: Preventing a From from Resizing

In some cases, developers would want to create a regular window (Form) in Delphi that contains some of the characteristics of a dialog box. For example, they do not want to allow their users to resize the form at runtime due to user interface design issues. Other than creating the whole form as a dialog box, there is not a property or a method to handle this in a regular window in Delphi. But due to the solid connection between Delphi and the API layer, developers can accomplish this easily.

The following example demonstrates a way of handling the Windows message "WM_GetMinMaxInfo" which allows the developer to restrict the size of windows (forms) at runtime to a specific value. In this case, it will be used to disable the functionality of sizing the window (form) at runtime.

Consider the following unit:


unit getminmax;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs;

type
TForm1 = class(TForm)

private
{ Private declarations }
procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
message WM_GETMINMAXINFO;
procedure WMInitMenuPopup(var Msg: TWMInitMenuPopup);
message WM_INITMENUPOPUP;
procedure WMNCHitTest(var Msg: TWMNCHitTest);
message WM_NCHitTest;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
begin
inherited;
with Msg.MinMaxInfo^ do
begin
ptMinTrackSize.x:= form1.width;

ptMaxTrackSize.x:= form1.width;
ptMinTrackSize.y:= form1.height;
ptMaxTrackSize.y:= form1.height;
end;
end;

procedure TForm1.WMInitMenuPopup(var Msg: TWMInitMenuPopup);
begin
inherited;
if Msg.SystemMenu then
EnableMenuItem(Msg.MenuPopup, SC_SIZE, MF_BYCOMMAND or MF_GRAYED)
end;

procedure TForm1.WMNCHitTest(var Msg: TWMNCHitTest);
begin
inherited;
with Msg do
if Result in [HTLEFT, HTRIGHT, HTBOTTOM, HTBOTTOMRIGHT,
HTBOTTOMLEFT, HTTOP, HTTOPRIGHT, HTTOPLEFT] then

Result:= HTNOWHERE
end;
end. { End of Unit}

A message handler for the windows message "WM_GetMinMaxInfo" in the code above was used to set the minimum and maximum TrackSize of the window to equal the width and height of the form at design time. That was actually enough to disable the resizing of the window (form), but the example went on to handle another couple of messages just to make the application look professional. The first message was the "WMInitMenuPopup" and that was to gray out the size option from the System Menu so that the application does not give the impression that this functionality is available. The second message was the "WMNCHitTest" and that was used to disable the change of the cursor icon whenever the mouse goes over one of the borders of the window (form) for the same reason which is not to give the impression that the resizing functionality is available.

messagedlg centering

From: "Jonathan M. Bell" Create your own procedure.
// Custom coding for The Knoxville News-Sentinel
//
// jmb 06/28/97 Completed MessageDlgCtr - centers message dialogs above
form

unit kns;

{$R-}

interface

uses Forms, Dialogs;

{ Centered message dialog }
function MessageDlgCtr(const Msg: string; DlgType: TMsgDlgType;
Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;

implementation

uses Consts;

{ This MessageDlg function centers the dialog above the active form }

function MessageDlgCtr(const Msg: string; DlgType: TMsgDlgType;
Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
begin
with CreateMessageDialog(Msg, DlgType, Buttons) do
try
HelpContext := HelpCtx;
Left := Screen.ActiveForm.Left + (Screen.ActiveForm.Width div 2) -
(Width div 2);
Top := Screen.ActiveForm.Top + (Screen.ActiveForm.Height div 2) -
(Height div 2);
Result := ShowModal;
finally
Free;
end;
end;

end.

Center a Form

I had a problem with centering a form after I had changed its dimensions
at run-time. The poScreenCenter only works when the form is shown. But
if you change the dimensions at run time your form doesn't center
automatically.
[Robert Meek, rmeek@ptdprolog.net]

I've used this in my FormCreate, but I guess it could be called during an OnPaint whenever you change the size of the form too couldn't it?


 Form1.Left := (Screen.Width  div 2) - (Form.Width div 2);
Form1.Top := (Screen.Height div 2) - (Form.Height div 2);

[Giuseppe Madaffari, giumad@antares.it]

if you use SetBounds, form won't be repainted twice (one time for Left assignment and other time for Top assignment).
Try:


procedure CenterForm(AForm:TForm);
var ALeft,ATop:Integer;
begin
ALeft := (Screen.Width - AForm.Width) div 2;
ATop := (Screen.Height - AForm.Height) div 2;
AForm.SetBounds(ALeft, ATop, AForm.Widht, AForm.Height);
end;

[Jaycen Dale, Jaycen@infoafrica.co.za]


Procedure CenterForm(aForm: TForm);
Begin
aform.left := (screen.width - aform.width) shr 1;
aform.top := (screen.height - aform.height) shr 1;
End;


Please email me and tell me if you liked this page.
Last modified 03/17/2007 21:36:59

This page has been created with HomeSite 2.5b

Delphi : DateUtils.pas 날짜함수 정리

http://www.delmadang.com/community/bbs_view.asp?bbsNo=21&bbsCat=0&indx=209893&page=41 델파이에 날짜함수를 모아둔 DateUtils.pas 가 있습니다. ...