[php+mysql]백만건 게시판 만들기

php 스쿨에 올라왔던 내용입니다.
아래의 알고리즘에 따라 제가 만들어본 테스트 사이트입니다.
http://222.112.187.32:9090:8080/blueboard/list.php?tbn=test

테스트 데이터를 넣는데 10만건 한번에 넣으니까 내 컴퓨터가 다운 되는군여..
5만건씩 넣다보니까 시간이 마니 걸려서.. 아직 데이터가 백만건 안됩니다만 시간나는대로 백만건 넣고 테스트해보져.

UID : 자동증가필드
PID : 정렬필드(인덱스)
THREAD : 응답글의 깊이

최초 등록글은
UID : 1
PID : 9999999.0000
THREAD : 0
이 됩니다.

두번째 등록글은
UID : 2
PID : 9999998.0000
THREAD : 0

첫번째 등록글에 답변글을 달면
UID : 3
PID : 9999999.0001
THREAD : 1
이 됩니다.

첫번째 등록글의 답변글에 답변을 달면
UID : 4
PID : 9999999.0002
THREAD : 2
가 됩니다..
원본글의 PID 에 0.0001 을 더해주고
원본글의 THREAD 에 1 을 더해줍니다.

첫번째 등록글의 첫번째답변글에 답변을 달면
UID : 5
PID : 9999999.0002
THREAD : 2
가 되고 이때, 답변글의 PID 를 업데이트 합니다..
PID
———–
9999999.0000
9999999.0001
9999999.0002

에서 9999999.0001 에 답변을 달면
그 답변글의 PID 는 + 0.0001 을 통해 9999999.0002 로 등록해 주고
이미 있었던 9999999.0002 는 + 0.0001 을 통해 9999999.0003 으로 업데이트해 줍니다..

일반적인 업데이트 게시판에서 10만개의 게시물이 있을때 1번글에 답변을 달면 99999개의 게시물을 업데이트해야 하므로 글등록속도가 상당히 느려지는데요..

위와 같은 경우 10만개는 물론 100만개일찌라도 전체를 업데이트하지 않고
PID 중 소수점이상이 같은 게시물에 대해서만 업데이트를 하므로 글등록에 따른 속도저하가 없습니다.

일반글 등록시는

$PID_NUM = mysql_fetch_array(mysql_query(“SELECT min(PID) FROM $table”, $DB_CONNECT));
if($PID_NUM[0]) {$PID = $PID_NUM[0] – 1;} else {$PID = 9999999.0000;}

답변글 등록시는

$REPLY_DATA = mysql_fetch_array(mysql_query(“SELECT * FROM $table WHERE UID=’$원본글의UID값'”,$DB_CONNECT));
if($REPLY_DATA[PID]) {
$PID = $REPLY_DATA[PID] + 0.0001;
$DPID = $REPLY_DATA[PID];
$UPID = intval($PID)+1;
$THREAD = $REPLY_DATA[THREAD] + 1;

mysql_query(“UPDATE myplus_$table SET PID=PID+0.0001 WHERE PID > $DPID AND PID < $UPID",$DB_CONNECT) or die(mysql_error()); 본알고리즘은 소수점을 이용하면서 답변글만 업데이트하는 방식이구요.. 기본이 ASC 정렬이므로 속도에 있어서도 개선이 있습니다.. 문제가 있다면 9999999개를 넘어서는 원본글이 등록되는 경우와 하나의 원본글에 답변글이 9999개 이상이 달리는 경우입니다.. 이 두문제는 거의 희박하겠지요.. 하지만 위의 알고리즘으로만 하다보면 문제점이 있습니다. 첨 페이지들은 무쟈게 속도가 나오지만 뒤로 갈수록 속도 저하가 상당하져.. 10만건까지는 마지막페이지가 1초정도 나오지만.. 15만건 정도 되니까.. 60초까지 나오는 군여.. 이상의 방법이 첫리스트를 뽑아오는데는 최상의 속도를 낼 수 있지만 반업데이트형 알고리즘의 취약점인 뒤쪽으로 갈 수록 페이징이 급격히 느려지는 현상 즉 절대로 LIMIT 100000,20 과 같은 LIMIT 으로는 뒷페이지에서 속도를 낼 수 없습니다. 그래서 where절에 PID의 시작포인트로 걸러주는게 필요합니다. $RECNUM = 15; //한페이지당 출력수 $START_NUM = ($p-1)*$RECNUM; // 페이지분할시작점 $TEMP_DATA = mysql_fetch_array(mysql_query("SELECT PID FROM $table ORDER BY PID LIMIT $START_NUM,1", $DB_CONNECT)); // INDEX가 걸린 PID를 정렬시켜 레코드 하나만 불러옵니다. $S_PID = $TEMP_DATA[PID]-0.0001; //시작포인트에서 0.0001을 빼줍니다. if(!$START_NUM) $S_PID = intval($S_PID)-1; //첫번째페이지라면 1을 빼줍니다. // 이상을 통해 $S_PID, 즉 PID 의 시작포인트를 알아냈습니다. $TABLE_DATA = mysql_query("SELECT * FROM $table WHERE PID > $S_PID ORDER BY $sort $orderby LIMIT 0,$RECNUM”, $DB_CONNECT);
// PID 시작포인트보다 PID 가 큰글을 LIMIT 0,$RECNUM 을 통해 $RECNUM만큼만 뽑아옵니다..
// 이때, 항상 LIMIT 0,$RECNUM 을 이용하므로 속도가 저하되지 않습니다.
// 문제는 $S_PID 를 구할때 인덱스가 걸려있다고 해도 LIMIT 1000000,1 을
// 사용하므로 속도가 떨어지는데.. 이 수치는 게시물 100만건일때 마지막페이지를
// 불러오는 속도가 대략 0.7~1 초 정도되는군요..
// 100만건에서 마지막 페이지가 1초이내이면 그런대로 만족할만한 수치입니다.
// 물론 손을 더 보아야 할 것 같습니다…

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다