http://211.174.53.89/~kims/kimsbbs/bbs.php?table=kims
http://211.174.53.89/~kims/kimsbbs/bbs/skin/default/skin.js
skin.js 내용
//타입비교
function getTypeCheck (s, spc)
{
var i;
for(i=0; i< s.length; i++)
{
if (spc.indexOf(s.substring(i, i+1)) < 0)
{
return false;
}
}
return true;
}
//호출파일
function getThisFile()
{
var QuerySplit = location.href.split('?');
return QuerySplit[0];
}
//파라미터값
function getUriString(param)
{
var QuerySplit = location.href.split('?');
var ResultQuer = QuerySplit[1].split('&');
for (var i = 0; i < ResultQuer.length; i++)
{
var keyval = ResultQuer[i].split('=');
if (param == keyval[0]) return keyval[1];
}
return "";
}
//검색셀렉트셋팅
function Search_Select()
{
var now_que = getPageGo(-1);
var now_where = getUriString('where');
if (now_que.indexOf('where='+now_where) != -1)
{
var where = document.all.search_where;
for (var i = 0; i < where.length; i++)
{
if (where[i].value == now_where)
{
where[i].selected = true;
}
}
}
document.all.search_keyword.value = getUriString('keyword');
document.all.search_keyword.focus();
}
//목록으로
function getListPage()
{
var now_param = location.href;
var delparam1 = "&query=" + getUriString('query');
var delparam2 = "&uid=" + getUriString('uid');
location.href = now_param.replace(delparam1,'').replace(delparam2,'');
}
//일반글쓰기
function getWritePage()
{
var table = getUriString('table');
location.href = getThisFile() + "?table=" + table + "&query=write";
}
//답변쓰기
function getReplyPage()
{
var now_param = location.href;
var delparam1 = "&query=" + getUriString('query');
location.href = now_param.replace(delparam1,'&query=write&write_type=reply');
}
//마지막페이지수
function LastPage(p)
{
return document.all.LastPage.innerHTML;
}
function View_Article(uid)
{
var p = getUriString('p');
var que = getPageGo(-1).replace('query=list&' , '');
location.href = que + '&query=view&p='+p+'&uid='+uid;
}
//검색
function getSearch(type)
{
if (type != 'detail')
{
if (event.keyCode != 0 && event.keyCode != 13) { return false; }
var now_whe = "&where="+getUriString('where');
var now_key = "&keyword="+getUriString('keyword');
var que = getPageGo(-1).replace(now_whe,'').replace(now_key,'');
var where = document.all.search_where.value;
var keyword = document.all.search_keyword.value;
if (keyword.length < 2)
{
alert('\n검색어를 입력하지 않으셨거나 너무 짧습니다. \n');
document.all.search_keyword.focus();
return false;
}
switch (type)
{
case "keyword" :
var nowstep = getUriString('search_step');
var nexstep = 1;
var delstep = "&search_step="+getUriString('search_step');
location.href = que.replace(delstep,'') + '&where=' + where + '&keyword=' + keyword + '&search_step=' + nexstep;
break;
case "prevsearch" :
var nowstep = getUriString('search_step');
var nexstep = nowstep ? parseInt(nowstep) - 1 : 1;
var delstep = "&search_step="+getUriString('search_step');
location.href = que.replace(delstep,'') + '&where=' + where + '&keyword=' + keyword + '&search_step=' + nexstep;
break;
case "nextsearch" :
var nowstep = getUriString('search_step');
var nexstep = nowstep ? parseInt(nowstep) + 1 : 2;
var delstep = "&search_step="+getUriString('search_step');
location.href = que.replace(delstep,'') + '&where=' + where + '&keyword=' + keyword + '&search_step=' + nexstep;
break;
}
}
else
{
}
}
//페이지이동
function PageSkip(type)
{
var p;
var startP = 1;
var finishP = LastPage(0);
switch (type)
{
case "start" : p = startP; break;
case "last" : p = finishP; break;
case "jump" : p = document.all.jump_page.value; break;
case "reset" : p = -1; break;
}
if (p < 0)
{
var table = getUriString('table');
var urlexp = location.href.split('?');
location.href = urlexp[0] + '?table=' + table + '&p=1';
return false;
}
if (event.keyCode != 0 && event.keyCode != 13)
{
return false;
}
if (!p) {
alert('이동할 페이지의 숫자를 입력해 주세요.');
document.all.jump_page.focus();
return false;
}
if(!getTypeCheck(p , "0123456789"))
{
alert('숫자만 입력해 주세요');
document.all.jump_page.value = "";
document.all.jump_page.focus();
return false;
}
if (finishP && parseInt(p) > parseInt(finishP)) p = finishP;
getPageGo(p);
}
//페이징처리
function getPageLink(lnum,p,tpage,imgpath)
{
var g_p1 = "<IMG src='"+imgpath+"/prev1.gif' border='0' ALIGN=ABSMIDDLE>";
var g_p2 = "<IMG src='"+imgpath+"/prev2.gif' border='0' ALIGN=ABSMIDDLE>";
var g_n1 = "<IMG src='"+imgpath+"/next1.gif' border='0' ALIGN=ABSMIDDLE>";
var g_n2 = "<IMG src='"+imgpath+"/next2.gif' border='0' ALIGN=ABSMIDDLE>";
var g_cn = "<IMG src='"+imgpath+"/cutln.gif' border='0' ALIGN=ABSMIDDLE>";
var g_q = "";
if(p < lnum+1) { g_q += g_p1; }
else{ var pp = parseInt((p-1)/lnum)*lnum; g_q += "<A HREF='javascript:getPageGo("+pp+");'>"+g_p2+"</A>";} g_q += g_cn;
var st1 = parseInt((p-1)/lnum)*lnum + 1;
var st2 = st1 + lnum;
for(var jn = st1; jn < st2; jn++)
if ( jn <= tpage)
(jn == p)? g_q += "<FONT COLOR=RED>"+jn+"</FONT>"+g_cn : g_q += "<A HREF='javascript:getPageGo("+jn+");'>"+jn+"</A>"+g_cn;
if(tpage < lnum || tpage < jn) { g_q += g_n1; }
else{var np = jn; g_q += "<A HREF='javascript:getPageGo("+np+");'>"+g_n2+"</A>"; }
document.write(g_q);
}
//페이지클릭
function getPageGo(n)
{
var que = location.href.replace("&p="+getUriString('p'),'');
if(n > 0)
{
location.href= que + '&p=' + n;
}
else{
return que;
}
}
//검색결과 하이라이트
function getKeywordHighLight()
{
var where = getUriString('where');
var keyword = getUriString('keyword');
var r,i,s=document.selection.createRange().text;
if(!where || !keyword)
{
return false;
}
var keyexp = keyword.split(' ');
for ( var j = 0; j < keyexp.length; j++)
{
r = document.body.createTextRange();
for(i = 0; r.findText(keyexp[j]); i++)
{
r.execCommand('ForeColor','','#FF0000');
r.execCommand('BackColor','','#FFFF00');
r.collapse(false);
}
}
}
//삭제체크
function Delchek(pid)
{
if(confirm('정말로 삭제하시겠습니까? '))
{
var table = getUriString('table');
var cqurl = location.href.replace("&query="+getUriString('query'),'');
cqurl = cqurl + "&action=delete&pid=" + pid;
location.href = cqurl;
}
}
안녕하세요..
계층형 구조에서 어떻게 하면 빠른 실행을 할 수 있을까에 대해 삽질이란 삽질은 다 해보고 이제 어느정도 구조가 정리되어 테스트를 요청하기 위해 글을 올립니다.
팁/텍 게시판인데 테스트 요청글을 올린 것 미리 양해말씀드립니다..
이곳의 팁/텍 및 포럼 게시판을 검색해 보면 계층형 구조에 대한 많은 팁들이 올라와 있는 것을 볼 수 있는데 대부분 결정적인 부분에서 문제가 생기는 구조였습니다..
속도만 놓고 볼때, 가장 빠를 수 있는 방법은 리스트에서 시작점만 알면 된다는 것인데, 이 부분이 애매하기 때문에 여기에 중점을 두었습니다..
대부분의 업데이트형 구조와 유사하지만 구분키를 두어 특정 레코드마다 몇번째 레코드인지의 정보를 기록해 두고 삭제나 답변시에 그 정보만 업데이트하였습니다..
구분키는 10000 단위로 하였고 따라서 1000만개라고 할때 1000개의 구분키가 포함됩니다..
1000개 정도되니까 마지막부분에서 그래도 부담이 되더군요... 구분키 100개 정도의 100만개 정도에서는 아주 깔끔하게 돌아갑니다..
table 은 하나만 사용하며 페이징이나 기타 잡다한 조건식은 java script 를 이용하였습니다..
로직에 문제가 없다면 공개해 드리겠습니다..
사용된 javascript 파일 : http://211.174.53.89/~kims/kimsbbs/bbs/skin/default/skin.js
----------------------------------------------------------------------------------
중요한 필드로는 UID , PID , KEY , DEPTH 가 있습니다..
UID 는 auto 키이고 PID 는 레코드 출력순서를 결정하는 인덱스필드입니다.
KEY 는 저장갯수가 10000개씩 증가할때 마다 그 필드만 업데이트를 합니다. DEPTH는 일반적인 답변글 깊이입니다.
PID 는 BIGINT 형이며 99999999000 이 초기값입니다..
즉, 원본글은 1000단위로 마이너스를 답변글은 1 단위로 플러스를 해 줍니다.
이때, 삭제나 답변이 있을 경우에는 KEY 값을 한칸씩 밀어주거나 당겨줘서 특정 부분의 시작PID 를 얻어낼 수 있는 것입니다..
PID : 1 2 3 4 5 6 7 8 9 10
------------------------------------
KEY : 10 0 0 0 5 0 0 0 0 0
위와 같은 구조에서 PID는 순서대로 저장하고 KEY 만 앞뒤로 옮겨주는 형태입니다.
그런데, 이 것도 테스트에서 처럼 1000만개 정도가 되면 업데이트를 위해 1000개의 쿼리를 날려야 하므로 완벽한 해결이 되지는 못하는 것 같구요.. 그래서 PID 와 KEY 필드를 분리하여 익덱스 테이블로 구분하는 작업을 하고 있습니다..
----------------------------------------------------------------------------------
올려드린 자바스크립트 파일은 일반적인 게시판이나 페이징등의 작업을 할때 사용하시면 유횽할 것입니다..
예를들어 페이징같은 경우 서버에서 PHP로 처리할 경우 0.05 초 이상은 잡게 됩니다..
이 것을 JS 로 처리하면 조금이나마 부담을 줄여줄 수 있을 것입니다..
첨부파일에서 getPageLink() 함수를 적당한 곳에 삽입해 주시고 , php로 페이징처리했던 부분에
<script>
getPageLink(<?=$lnum?>,<?=$p;?>,<?=$Tot_Page?>,"./bbs/image/ico");
</script>
위의 코드를 삽입해 주세요..
$lnum 은 한페이지 몇개의 페이지링크 번호를 만들것인가
$p 는 현재호출페이지
$Total_Page 는 총게시물수 / 한페이지당 출력수
./bb/image/ico 는 이전/다음등의 이미지 경로입니다.
이외에도 getUriString(param) 등의 함수는 매우 유용하게 사용할 수 있을 것입니다.
덧글 :
대부분의 업데이트형 구조와 유사하지만 구분키를 두어 특정 레코드마다 몇번째 레코드인지의 정보를 기록해 두고 삭제나 답변시에 그 정보만 업데이트하였습니다..
어떻게 업데이트 하는건지 알려주세요(조름 모드.. ^^) 100만개의 글에서 첫번째 글에 리플이 달릴때 99만 9999개를 업뎃하는게 아니라 구분키만 업뎃 한다는 것인가여? 99개가 되네여
덧글 :
저도 생각하고 구현중인 알고리즘인데, 새로운 시도는 아닌 것 같습니다. 그 생각한지가 벌써 몇 달 되었는데, 그 전에 이미 다른분이 올린 글도 있더라구요. *^^*
이게 roop4ng님이 올리신 원칼럼 답글알고리즘.
http://phpschool.com/bbs2/inc_view.html?id=6343&code=tnt2&start=60&mode=search&field=title&search_name=&operator=and&period=all&category_id=&s_que=%B0%D4%BD%C3%C6%C7
이게 q님이 올리셨던 그룹내의 게시물갯수 계산법
http://phpschool.com/bbs2/inc_view.html?id=9125&code=tnt2&start=30&mode=search&field=title&search_name=&operator=and&period=all&category_id=&s_que=%B0%D4%BD%C3%C6%C7
두개를 합치면... 김성호님의 알고리즘이 나옵니다.
저도 스스로 생각했을때는 참 괜찮은 것 같다...고 생각했었는데, 이미 다른 분들이 1, 2년전에 다 생각했던 거더군요(그럼 그렇지 제 주제에 무슨... ㅠ_ㅠ).
어쨌거나... 역시 스쿨의 힘은 대단한 것 같습니다.
덧글 :
음.. 분할 인덱스 맞군요....
http://phpschool.com/bbs2/inc_view.html?id=10415&code=tnt2&start=0&mode=search&field=name&search_name=&operator=and&period=all&category_id=&s_que=ezmaster
이 게시물과 많이 비슷 하네요..
아무래도 속도를 높이기 위해서 풀검색이 빠졌기 때문에
아자씨님의 문제도 역시 풀정렬로는 힘들것으로 생각됩니다.
분할값 안에서만 처리가 가능 하겠군요..
음.. 그런데 분할값 안에서 limit를 쓰지 않고 pid를 구하나 보군요?. 중간에 겹치는 부분에서도 속도가 전혀 떨어지지 않는군요.. 흐음..
출처 : phpschool
'SQL' 카테고리의 다른 글
| group by 절에서의 조건절(case처리) (0) | 2007/06/07 |
|---|---|
| [SQL 2K Books Online 5월 4일자 Update 다운로드] (0) | 2007/06/07 |
| 대용량 계층형 게시판 원리들 (0) | 2007/06/07 |
| 검색 방법 - 역인덱스 (0) | 2007/06/07 |
| MSSQL Server 2000의 오류처리 기법 (0) | 2007/06/07 |
| 문자열을 테이블 또는 배열로 저장하는 SQL 스크립트 (0) | 2007/06/07 |




최근에 달린 댓글
링크
최근에 받은 트랙백
태그목록