GIS-based Spatial Analysis for the Geosciences: Geospatial Correlative Integration
'JOB' 카테고리의 다른 글
Linux APM설치 - Apache2,PHP5,MYSQL (1) | 2008.12.25 |
---|
GIS-based Spatial Analysis for the Geosciences: Geospatial Correlative Integration
Linux APM설치 - Apache2,PHP5,MYSQL (1) | 2008.12.25 |
---|
app 배포방법 (0) | 2010.06.28 |
---|---|
SSH 파일전송 받기 (0) | 2010.06.28 |
find 명령 (0) | 2010.05.28 |
안녕하세요? 네이버 OpenAPI 담당자 입니다.
PHP를 이용하는 경우 주소 뒤에 붙게 되는 인수의 처리를 코드에 직접 삽입하는 경우가 많습니다.
10개 이내의 경우에 견딜만 하지만 10개가 넘어가기 시작하면 감당하기가 힘듭니다.
이 경우에는 http_build_query 함수와 $_GET 변수를 이용하면 도움이 됩니다.
예를 들어, 큰 love과 관련된 최신 이미지를 20개씩 검색하고 싶은 경우에 아래와 같은 URL 패턴을 만들게 됩니다.
http://openapi.naver.com/search?key=openapi&target=image&query=love&display=20&start=1&sort=date&filter=large
위 URL은 $_GET 변수에 배열로 저장되어 있습니다.
이것을 다시 URL로 만들고자 하는 경우에 http_build_query($_GET)을 사용하시면 기존의 URL 인수인 key=openapi&target=image&query=love&display=20&start=1&sort=date&filter=large 를 만들게 됩니다.
만약에 다음 페이지를 보고 싶은 경우에 어떻게 해야 할까요?
아래와 같은 방법을 사용하시면 편리하게 사용할 수 있습니다.
$params = $_GET;
$params['start'] += $images['display'];
$url_param = http_build_query($params);
display 되는 개수를 start 값에 더해주면 다음 페이지에 필요한 start 값을 알 수 있습니다.
그렇게 생성된 url_params를 이용하여 http://openapi.naver.com/search? 뒤에 붙여주면 되겠죠?
물론, 검색키는 항상 숨겨두셔야 하는 것! 잊지 마세요 :)
해당 함수는 PHP 5.1.2 버전 이상에서 사용할 수 있습니다.
php 설정에 따라서 & 형식으로 나오는 경우에는
php.ini 파일에서 arg_separator 를 변경하시거나,
ini_set('arg_separator.output', '&');을 수행 후 이용할 수 있습니다.
※ Python 에서는 urllib.urlencode() 함수를 이용하시면 됩니다.
eAccelerator 설치 (0) | 2010.04.16 |
---|---|
[날짜] 시작일~종료일 사이의 날짜 출력 (0) | 2008.06.20 |
DOWNLOAD :http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/winsoft.html
1. instantclient-basic , instantclient-SQL*Plus , SDK 등 다운로드
2. 적당한 위에 압축 풀기
C:\instantclient_10_2
3. tnsnames.ora 생성
C:\instantclient_10_2\network\ 에 생성.
ORADB =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 211.42.87.150)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = NONGUP)
)
)
4. 환경변수 설정
* PATH : C:\instantclient_10_2 추가.
* ORACLE_HOME : C:\instantclient_10_2 신규 추가.
* TNS_ADMIN : C:\instantclient_10_2\network 신규추가.
5. 레지스트리 추가
KOREAN_KOREA.KO16KSC5601
* 서버쪽 NLS_LANG 과 같게 셋팅.
게시판에 대한 쿼리 및 인덱스 작성 방법 (0) | 2010.03.19 |
---|---|
계층형 게시판의 테이블 구조와 알고리즘 - 두번째 (0) | 2010.03.19 |
게시판에 대한 쿼리 및 인덱스 작성 방법 (0) | 2010.03.19 |
생성된 인덱스 정보 보기 (0) | 2010.03.19 |
[MSSQL 2000] 백업 및 복구 (1) | 2008.06.23 |
app.tar 다른 시스템으로 카피 후
1.# useradd –M mysql 계정생성
2.# chown –R mysql /app/dbms/mysql
# chgrp –R mysql /app/dbms/mysql
3.# chcon -t texrel_shlib_t /app/apache/modules/libphp5.so
4.# groupadd oinstall
# groupadd dba
# useradd –g oinstall -G dba oracle
# passwd oracle
# chown –R oracle.oinstall /app/dbms/oracle
5. /app/apache/bin/apachectl –t 확인 후 아파치 시작
/app/apache/logs/error_log 파일 참고
* chcon -t texrel_shlib_t /app/php5/lib/php/extensions/mysql.so
* chcon -t texrel_shlib_t /app/php5/lib/php/extensions/oci8.so
* chcon -t texrel_shlib_t /app/php5/lib/php/extensions/xmlrpc.so
* chcon -t texrel_shlib_t /app/php5/lib/php/extensions/cubrid.so
* chcon -t texrel_shlib_t /app/dbms/oracle/product/10.2.0/db_1/lib/libnnz10.so
* chcon -t texrel_shlib_t /app/dbms/oracle/product/10.2.0/db_1/lib/libclntsh.so.10.1
6. scp –P 포트 root@192.168.0.xx;/etc/my.cnf /etc/ my.cnf 파일을 복사
SVN 추가방법 (0) | 2010.07.22 |
---|---|
SSH 파일전송 받기 (0) | 2010.06.28 |
find 명령 (0) | 2010.05.28 |
출처 : http://sukhoi.springnote.com/pages/1712582
[출처]
[linux] find 사용 예|작성자 jinSVN 추가방법 (0) | 2010.07.22 |
---|---|
app 배포방법 (0) | 2010.06.28 |
SSH 파일전송 받기 (0) | 2010.06.28 |
aix 5.3
export PHP_PREFIX="/web/app/php5"
$PHP_PREFIX/bin/phpize
./configure --enable-eaccelerator=shared \
--with-eaccelerator-userid=root \ <=== 에러발생하여 추가한부분
--with-php-config=$PHP_PREFIX/bin/php-config
make
make install
/web/app/php5/lib/php/extensions/no-debug-non-zts-20060613
eaccelerator.so 파일 확인
php.ini 에
========================================================================
extension=eaccelerator.so
zend_extension="/web/app/php5/lib/php/extensions/no-debug-non-zts-20060613/eaccelerator.so" <-- Linux인 경우만 추가. 설치경로와 맞게 지정
eaccelerator.shm_size="16"
eaccelerator.cache_dir="/var/tmp/eaccelerator"
eaccelerator.enable="1"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="1"
eaccelerator.debug="0"
eaccelerator.filter=""
eaccelerator.shm_max="0"
eaccelerator.shm_ttl="0"
eaccelerator.shm_prune_period="0"
eaccelerator.shm_only="0"
eaccelerator.compress="1"
eaccelerator.compress_level="9"
mkdir /htdoc/cache
chown nobody cache
chmod 0700 cache
PHP의 URL 변수 관리 [출처] [TIP] PHP의 URL 변수 관리 (네이버 OpenAPI 공식 카페) |작성자 openapi (0) | 2010.07.22 |
---|---|
[날짜] 시작일~종료일 사이의 날짜 출력 (0) | 2008.06.20 |
웹 개발자들을 대상으로 교육을 하다보면, 게시판에 대한 빠른 검색방법에 대하여 많은 질문을 받습니다. 아마도 웹 개발자들이 처음으로 구축하게 되는 예제가 게시판이어서 그런것 같습니다.
먼저, 게시판의 종류는 답글(질의응답)과 댓글(리플) 없는 자유게시판에서부터 답글이 있는 계층형(질의응답) 게시판, 댓글이 포함되는 게시판, 요즘에는 댓글도 계층형으로 구성되는 게시판도 있습니다.
여기서는 가장 간단한 자유 게시판을 예로 들어, 쿼리와 인덱스 작성에 대하여 알아보겠습니다.
실습을 위해 테이블을 다음과 같이 생성하였습니다.
create table freeboard
(no number,
subject varchar2(100),
content varchar2(4000));
게시판의 일련 번호 부여를 위해 시퀀스를 작성했습니다.
create sequence freeboard_no_seq
start with 1
increment by 1;
게시판의 성능 테스트를 위해서 10만건의 게시물을 입력하였습니다.
begin
for i in 1..100000 loop
insert into freeboard values(freeboard_no_seq.nextval, i||'번째 게시물 제목', lpad('*', 500, '*'));
commit;
end loop;
end;
/
쿼리의 성능 측정을 위해 AUTOTRACE를 사용하기로 하였습니다. 먼저, plustrace 롤을 만들어 사용자에게 부여하고, 실행계획이 저장될 plan_table을 생성하였습니다.
connect / as sysdba
@C:\oracle\product\10.2.0\db_1\sqlplus\admin\plustrce.sql
grant plustrace to scott;
connect scott/tiger
@C:\oracle\product\10.2.0\db_1\rdbms\admin\utlxplan.sql
set autotrace traceonly
<인덱스가 없는 상태에서 5만번째 게시물을 검색해봅니다.>
select no, subject, content from freeboard
where no=50000;
주의 깊게 보아야 할 내용은 다음과 같습니다.
Execution Plan
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 528 | 1708 (1)| 00:00:21 |
|* 1 | TABLE ACCESS FULL| FREEBOARD | 1 | 528 | 1708 (1)| 00:00:21 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
165 recursive calls
0 db block gets
7769 consistent gets
0 physical reads
0 redo size
1058 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
1 rows processed
=> no 컬럼에 인덱스가 존재하지 않기 때문에 오라클의 옵티마이저는 Full Table Scan 방식을 선택하였으며, 읽어온 블럭의 갯수는 7769(=7769+0)개 입니다.
<이번엔 페이지당 표시되는 게시물을 20개로 가정하고, 게시판의 첫번째 페이지(글번호, 제목)를 검색해봅니다.>
select t2.no, t2.subject
from (select rownum rn, t1.no, t1.subject
from (select no, subject
from freeboard
order by no desc) t1
where rownum <= 1*20) t2
where rn >= (1-1)*20+1;
=> 서브 쿼리를 사용한 이유는 게시물이 삭제되면, 글번호가 연속적이지 않기 때문입니다.
Execution Plan
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 1560 | 1707 (1)| 00:00:21 |
|* 1 | VIEW | | 20 | 1560 | 1707 (1)| 00:00:21 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | VIEW | | 100K| 6347K| 1707 (1)| 00:00:21 |
|* 4 | SORT ORDER BY STOPKEY| | 100K| 2636K| 1707 (1)| 00:00:21 |
| 5 | TABLE ACCESS FULL | FREEBOARD | 100K| 2636K| 1707 (1)| 00:00:21 |
--------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
7750 consistent gets
0 physical reads
0 redo size
1251 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
20 rows processed
=> Full Table Scan 작업 후, 정렬 작업이 수행되었으며, 7750(=7750+0)개 블럭을 읽었습니다.
<마지막 페이지(5000번째) 검색>
select t2.no, t2.subject
from (select rownum rn, t1.no, t1.subject
from (select no, subject
from freeboard
order by no desc) t1
where rownum <= 5000*20) t2
where rn >= (5000-1)*20+1;
Execution Plan
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 7617K| | 2479 (2)| 00:00:30 |
|* 1 | VIEW | | 100K| 7617K| | 2479 (2)| 00:00:30 |
|* 2 | COUNT STOPKEY | | | | | | |
| 3 | VIEW | | 100K| 6347K| | 2479 (2)| 00:00:30 |
|* 4 | SORT ORDER BY STOPKEY| | 100K| 2636K| 7096K| 2479 (2)| 00:00:30 |
| 5 | TABLE ACCESS FULL | FREEBOARD | 100K| 2636K| | 1707 (1)| 00:00:21 |
----------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
7750 consistent gets
0 physical reads
0 redo size
1143 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
20 rows processed
=> 마찬가지로 Full Table Scan 작업 후, 정렬 작업이 수행되었으며, 7750(=7750+0)개 블럭을 읽었습니다.
게시판의 게시물은 일련 번호에 따라 내림차순으로 출력되어야 하므로 내림차순 인덱스를 구성합니다.
create unique index freeboard_no_idx on freeboard(no desc);
일련 번호에 대하여 기본키 제약조건을 설정합니다.
alter table freeboard
add constraint freeboard_no_pk primary key(no);
테이블 통계와 인덱스 통계를 수집합니다.
exec dbms_stats.gather_table_stats('scott', 'freeboard');
exec dbms_stats.gather_index_stats('scott', 'freeboard_no_idx');
<인덱스가 있는 상태에서 5만번째 게시물을 검색해봅니다.>
select no, subject, content from freeboard
where no=50000;
Execution Plan
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 528 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| FREEBOARD | 1 | 528 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | FREEBOARD_NO_PK | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
969 bytes sent via SQL*Net to client
374 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
=> 인덱스를 이용하여 검색하기 때문에 3(=3+0)개 블럭을 읽었습니다.
<페이지당 표시되는 게시물을 20개로 가정하고, 첫번째 페이지(글번호, 제목) 검색>
select t2.no, t2.subject
from (select rownum rn, t1.no, t1.subject
from (select no, subject
from freeboard
order by no desc) t1
where rownum <= 1*20) t2
where rn >= (1-1)*20+1;
Execution Plan
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 1560 | 4 (0)| 00:00:01 |
|* 1 | VIEW | | 20 | 1560 | 4 (0)| 00:00:01 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | VIEW | | 20 | 1300 | 4 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| FREEBOARD | 100K| 2636K| 4 (0)| 00:00:01 |
| 5 | INDEX FULL SCAN DESCENDING| FREEBOARD_NO_PK | 20 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
9 consistent gets
8 physical reads
0 redo size
1251 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
20 rows processed
=> 인덱스를 내림차순으로 구성하였기 때문에 정렬작업이 수행되지 않고 17(=9+8)개 블럭을 읽었습니다.
<마지막 페이지(5000번째) 검색>
select t2.no, t2.subject
from (select rownum rn, t1.no, t1.subject
from (select no, subject
from freeboard
order by no desc) t1
where rownum <= 5000*20) t2
where rn >= (5000-1)*20+1;
Execution Plan
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 7617K| | 2479 (2)| 00:00:30 |
|* 1 | VIEW | | 100K| 7617K| | 2479 (2)| 00:00:30 |
|* 2 | COUNT STOPKEY | | | | | | |
| 3 | VIEW | | 100K| 6347K| | 2479 (2)| 00:00:30 |
|* 4 | SORT ORDER BY STOPKEY| | 100K| 2636K| 7096K| 2479 (2)| 00:00:30 |
| 5 | TABLE ACCESS FULL | FREEBOARD | 100K| 2636K| | 1707 (1)| 00:00:21 |
----------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
7750 consistent gets
0 physical reads
0 redo size
1143 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
20 rows processed
=> 인덱스가 있지만, 오라클의 옵티마이저는 테이블 전체를 읽고 정렬을 수행하는 방법을 선택했습니다. 총 7750(=7750+0)개 블럭을 읽었습니다.
그렇다면, Hint를 주어 정렬 작업을 수행하지 않고 인덱스를 사용한 경우, 쿼리의 성능을 살펴보겠습니다.
select t2.no, t2.subject
from (select rownum rn, t1.no, t1.subject
from (select /*+ index(freeboard freeboard_no_idx) */ no, subject
from freeboard) t1
where rownum <= 5000*20) t2
where rn >= (5000-1)*20+1;
Execution Plan
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 7617K| 7932 (1)| 00:01:36 |
|* 1 | VIEW | | 100K| 7617K| 7932 (1)| 00:01:36 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| FREEBOARD | 100K| 2636K| 7932 (1)| 00:01:36 |
| 4 | INDEX FULL SCAN | FREEBOARD_NO_IDX | 100K| | 227 (2)| 00:00:03 |
--------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
7920 consistent gets
0 physical reads
0 redo size
1143 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
20 rows processed
=> 오라클 옵티마이저의 선택이 옳았습니다. 오히려, 더 많은 블럭(7920개)을 읽는군요.
어쨌든, 게시판에서 게시물을 글번호에 대한 Equal 조건으로 검색하는 경우, 오름차순이나 내림차순 인덱스와 관련없이
인덱스만 존재하면 검색속도는 충분히 보장 받을 수 있습니다. 그러나, 게시판을 최근 페이지 단위로 검색해야 하는 경우에는 인덱스를 내림차순으로 구성하여 정렬 작업을 피하는 편이 유리합니다. 물론, 오라클의 버전에 따라 오름차순 인덱스를 구성해도 옵티마이저가 인덱스를 역순으로 사용하여 정렬 작업을 회피하기도 하기 때문에 항상 실행계획을 확인하는 습관을 들이는것이 좋을 것 같습니다.
====================================================================
먼저, 내림차순으로 구성되어 있는 인덱스를 이용하여 5000번 페이지의 첫번째 글번호를 읽고,
마찬가지로 인덱스를 이용하여 20건을 읽어 보았습니다.
select /*+ index(freeboard freeboard_no_idx) */ no, subject
from freeboard
where no<=(select /*+ index(freeboard freeboard_no_idx) */ min(no)
from freeboard
where rownum <= (5000-1)*20+1)
and rownum<=20;
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 540 | 456 (2)| 00:00:06 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| FREEBOARD | 20 | 540 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | FREEBOARD_NO_IDX | 45 | | 2 (0)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 5 | | |
|* 5 | COUNT STOPKEY | | | | | |
| 6 | INDEX FULL SCAN | FREEBOARD_NO_IDX | 100K| 488K| 227 (2)| 00:00:03 |
-------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
231 consistent gets
0 physical reads
0 redo size
1143 bytes sent via SQL*Net to client
396 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
20 rows processed
결과에서 보면 가장 마지막 페이지를 읽기 위해 231개의 블럭을 읽게 되었군요.
좋은 아이디어 입니다.
기환씨 열심히 공부하고 계시죠. 파이팅입니다. 이상입니다.
instantclient 설치하기 (window) (0) | 2010.06.30 |
---|---|
계층형 게시판의 테이블 구조와 알고리즘 - 두번째 (0) | 2010.03.19 |
게시판에 대한 쿼리 및 인덱스 작성 방법 (0) | 2010.03.19 |
생성된 인덱스 정보 보기 (0) | 2010.03.19 |
[MSSQL 2000] 백업 및 복구 (1) | 2008.06.23 |
계층형 게시판을 위한 두번째 알고리즘에 대해서 알아봅니다.
첫번째 계층형 게시판에서는 같은 레벨에 답글을 다는 경우, 가장 최근 답글이 동일한 레벨에서 가장 위에 표시되었습니다.
이번에는 가장 최근 답글이 동일한 레벨에서 마지막에 표시되도록 합니다.
설명을 위해 테이블에는 다음과 같은 컬럼들만 있다고 가정합니다. 실제로는 더 많겠죠.
No : 글번호(Primary Key)
Title : 글제목
Grp : 같은 주제를 갖는 게시물의 고유번호. 부모글과 부모글로부터 파생된 모든 자식글은 같은 번호를 갖습니다.
Depth : 같은 그룹내 게시물의 순서
게시판에 첫번째 글이 올라오면, 테이블에는 다음과 같은 정보가 저장됩니다.
=================================
No, Title , Grp, Depth
=================================
1, '안녕하세요' , 1, 'A'
=================================
새 글에서 No는 시퀀스로부터 받아온 값, Grp는 No와 동일한 값, Depth는 'A'입니다.
두번째 글과 세번째 글이 올라옵니다.
=================================
No, Title , Grp, Depth
=================================
3, '모임이 있습니다', 3, 'A'
2, '날씨가 맑습니다', 2, 'A'
1, '안녕하세요 ', 1, 'A'
=================================
첫번째 글에 답글이 올라옵니다.
=================================
No, Title , Grp, Depth
=================================
3, '모임이 있습니다', 3, 'A'
2, '날씨가 맑습니다', 2, 'A'
1, '안녕하세요 ', 1, 'A'
4, ' 반가워요 ', 1, 'AA'
=================================
답글의 경우, Grp는 부모글의 Grp 값, Depth는 부모글의 Depth에 'A'를 추가합니다.
첫번째 글의 답글에 답글이 올라옵니다. 즉, 네번째 글의 답글이 올라옵니다.
=================================
No, Title , Grp, Depth
=================================
3, '모임이 있습니다', 3, 'A'
2, '날씨가 맑습니다', 2, 'A'
1, '안녕하세요 ', 1, 'A'
4, ' 반가워요 ', 1, 'AA'
5, ' 감사합니다 ', 1, 'AAA'
=================================
첫번째 글의 두번째 답글이 올라옵니다.
=================================
No, Title , Grp, Depth
=================================
3, '모임이 있습니다', 3, 'A'
2, '날씨가 맑습니다', 2, 'A'
1, '안녕하세요 ', 1, 'A'
4, ' 반가워요 ', 1, 'AA'
5, ' 감사합니다 ', 1, 'AAA'
6, ' 환영합니다 ', 1, 'AB'
=================================
여기서, 두번째 답글이 첫번째 답글의 아래에 표시되려면, 동일한 그룹 번호에 있으면서, 부모의 Depth 문자열로 시작되고,
문자열의 길이가 부모의 Depth 문자열보다 하나가 큰 문자열 중 최대값을 찾아 Depth로 사용합니다.
여섯번째 게시물에 답글이 올라옵니다.
=================================
No, Title , Grp, Depth
=================================
3, '모임이 있습니다', 3, 'A'
2, '날씨가 맑습니다', 2, 'A'
1, '안녕하세요 ', 1, 'A'
4, ' 반가워요 ', 1, 'AA'
5, ' 감사합니다 ', 1, 'AAA'
6, ' 환영합니다 ', 1, 'AB'
7, ' 감사합니다 ', 1, 'ABA'
=================================
네번째 게시물에 두번째 답글이 올라옵니다.
=================================
No, Title , Grp, Depth
=================================
3, '모임이 있습니다', 3, 'A'
2, '날씨가 맑습니다', 2, 'A'
1, '안녕하세요 ', 1, 'A'
4, ' 반가워요 ', 1, 'AA'
5, ' 감사합니다 ', 1, 'AAA'
8, ' 저도 방가 ', 1, 'AAB'
6, ' 환영합니다 ', 1, 'AB'
7, ' 감사합니다 ', 1, 'ABA'
=================================
검색 할 때는 Grp를 내림차순으로 Depth를 오름차 순으로 정렬하면 됩니다.
인덱스는 기본키와 Grp+Depth의 복합 인덱스를 설정하면 됩니다.
실제 오라클에서 테이블을 구성하고 검색해봅니다.
drop table qnaboard;
create table qnaboard
(no number,
title varchar2(100),
contents varchar2(4000),
writer varchar2(20),
wdate date,
grp number,
depth varchar2(1000));
drop sequence qnaboard_no_seq;
create sequence qnaboard_no_seq
start with 1
increment by 1;
create index qnaboard_no_idx on qnaboard(no) reverse;
alter table qnaboard
add constraint qnaboard_no_pk primary key (no);
문자열 처리를 위한 도우미 함수입니다. 문자열을 입력하면 마지막 문자를 다음 문자로 교체합니다.
예를 들어, 'AAABB'를 입력하면, 'AAABC'를 리턴합니다.
create or replace function next_depth(str varchar2)
return varchar2
as
v_str1 varchar2(32767);
v_str2 varchar2(32767);
begin
v_str1 := substr(str, 1, length(str)-1);
v_str2 := substr(str, -1, 1);
return v_str1||chr(ascii(v_str2)+1);
end;
/
create index qnaboard_grp_seq on qnaboard(grp desc, depth asc);
alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
첫번째 게시물 입력 - 새 글 입력
insert into qnaboard
values(qnaboard_no_seq.nextval, '안녕하세요', null, '길동', sysdate, qnaboard_no_seq.currval, 'A');
두번째 게시물 입력 - 새 글 입력
insert into qnaboard
values(qnaboard_no_seq.nextval, '날씨가 맑습니다', null, '철수', sysdate, qnaboard_no_seq.currval, 'A');
세번째 게시물 입력 - 새 글 입력
insert into qnaboard
values(qnaboard_no_seq.nextval, '모임이 있습니다', null, '영희', sysdate, qnaboard_no_seq.currval, 'A');
네번째 게시물 입력 - 첫번째 게시물의 답글
답글이 올라오는 경우에는 답글에 부여 할 depth를 결정해야 합니다.
이를 위해서, 부모글의 depth인 'A'로 다음과 같은 쿼리를 실행합니다.
select next_depth(max(depth))
from qnaboard
where grp=1
and depth like 'A_';
위의 쿼리가 null이면 답글에 부여 할 depth는 부모글의 depth에 'A'를 붙인 문자열이 됩니다.
insert into qnaboard
values(qnaboard_no_seq.nextval, '반가워요', null, '만수', sysdate, 1, 'AA');
다섯번째 게시물 입력 - 네번째 게시물의 답글
네번째 게시물의 depth는 'AA'입니다.
select next_depth(max(depth))
from qnaboard
where grp=1
and depth like 'AA_';
위의 쿼리가 null이므로 답글에 부여 할 depth는 부모글의 depth에 'A'를 붙인 'AAA'가 됩니다.
insert into qnaboard
values(qnaboard_no_seq.nextval, '감사합니다', null, '길동', sysdate, 1, 'AAA');
여섯번째 게시물 입력 - 첫번째 게시물의 두번째 답글
첫번째 게시물의 depth는 'A'입니다.
select next_depth(max(depth))
from qnaboard
where grp=1
and depth like 'A_';
위의 쿼리 리턴값 'AB'가 답글에 부여 할 depth가 됩니다.
insert into qnaboard
values(qnaboard_no_seq.nextval, '환영합니다', null, '찬호', sysdate, 1, 'AB');
일곱번째 게시물 입력 - 여섯번째 게시물의 답글
여섯번째 게시물의 depth는 'AB'입니다.
select next_depth(max(depth))
from qnaboard
where grp=1
and depth like 'AB_';
위의 쿼리가 null이므로 답글에 부여 할 depth는 부모글의 depth에 'A'를 붙인 'ABA'가 됩니다.
insert into qnaboard
values(qnaboard_no_seq.nextval, '감사합니다', null, '길동', sysdate, 1, 'ABA');
여덟번째 게시물 입력 - 네번째 게시물의 답글
네번째 게시물의 depth는 'AA'입니다.
select next_depth(max(depth))
from qnaboard
where grp=1
and depth like 'AA_';
위의 쿼리 리턴값 'AAB'가 답글에 부여 할 depth가 됩니다.
insert into qnaboard
values(qnaboard_no_seq.nextval, '저도 방가', null, '병헌', sysdate, 1, 'AAB');
게시판을 검색하는 경우, grp로 내림차순, seq로 오름차순으로 정렬하면 됩니다.
select
case when length(depth)-1=0 then no
when length(depth)-1>0 then null end no
, rpad('+', length(depth)-1, '-')||title title
, writer
, wdate
from qnaboard
order by grp desc, depth;
NO TITLE WRITER WDATE
---------- -------------------- -------------------- -------------------
3 모임이 있습니다 영희 2007-09-15 21:51:26
2 날씨가 맑습니다 철수 2007-09-15 21:51:03
1 안녕하세요 길동 2007-09-15 21:48:23
+반가워요 만수 2007-09-15 21:53:41
+-감사합니다 길동 2007-09-15 21:55:57
+-저도 방가 병헌 2007-09-15 22:03:27
+환영합니다 찬호 2007-09-15 21:57:55
+-감사합니다 길동 2007-09-15 21:59:49
instantclient 설치하기 (window) (0) | 2010.06.30 |
---|---|
게시판에 대한 쿼리 및 인덱스 작성 방법 (0) | 2010.03.19 |
게시판에 대한 쿼리 및 인덱스 작성 방법 (0) | 2010.03.19 |
생성된 인덱스 정보 보기 (0) | 2010.03.19 |
[MSSQL 2000] 백업 및 복구 (1) | 2008.06.23 |