재귀호출 쿼리 좀 도와주세요
본문
게시판 댓글 시스템 커스텀 테스트중입니다.
/bbs/view.comment.php 에서 댓글 불러오는 쿼리가 실행중이고,(1번 쿼리)
$sql = " select * from $write_table where wr_parent = '$wr_id' and wr_is_comment = 1 order by $orderby ";
/skin/board/basic/view_comment.skin.php 에서 대댓글을 불러오는 쿼리를 삽입했습니다. (2번 쿼리)
$sql2 = "SELECT * FROM {$table_nm} WHERE wr_parent = $comment_id AND wr_is_comment = 1 ORDER BY wr_id";
1번 쿼리가 실행중에 2번 쿼리가 재귀호출되니 DB에 부하가 엄청 걸려서 락이 많이 걸리네요.
댓글 불러오는 부분
for ($i=0; $i<$cmt_amt; $i++) {
$comment_id = $list[$i]['wr_id'];
$cmt_depth = strlen($list[$i]['wr_comment_reply']) * 50;
$comment = $list[$i]['content'];
/*
if (strstr($list[$i]['wr_option'], "secret")) {
$str = $str;
}
*/
$comment = preg_replace("/\[\<a\s.*href\=\"(http|https|ftp|mms)\:\/\/([^[:space:]]+)\.(mp3|wma|wmv|asf|asx|mpg|mpeg)\".*\<\/a\>\]/i", "<script>doc_write(obj_movie('$1://$2.$3'));</script>", $comment);
$cmt_sv = $cmt_amt - $i + 1; // 댓글 헤더 z-index 재설정 ie8 이하 사이드뷰 겹침 문제 해결
$c_reply_href = $comment_common_url.'&c_id='.$comment_id.'&w=c#bo_vc_w';
$c_edit_href = $comment_common_url.'&c_id='.$comment_id.'&w=cu#bo_vc_w';
$is_comment_reply_edit = ($list[$i]['is_reply'] || $list[$i]['is_edit'] || $list[$i]['is_del']) ? 1 : 0;
?>
<li>
<div class="info">
<span><?php echo $list[$i]['wr_name'] ?></span>
<div class="date">
<i><?php echo $list[$i]['datetime'] ?></i>
</div>
<div class="modify">
<?php if ($user['mb_id'] == $list[$i]['mb_id']) { ?>
<button type="button" class="btn_edit" data-key="<?php echo $comment_id ?>"><span class="blind">수정</span></button>
<button type="button" class="btn_remove" data-key="<?php echo $comment_id ?>"><span class="blind">삭제</span></button>
<?php } ?>
</div>
<div class="util">
<button type="button" class="btn_c_report" data-key="<?php echo $comment_id ?>">신고 <?php echo number_format($list[$i]['wr_nogood']) ?></button>
<button type="button" class="btn_reply" data-key="<?php echo $comment_id ?>">답글</button>
<button type="button" class="btn_reply_cancel" data-key="<?php echo $comment_id ?>">취소</button>
</div>
</div>
<div class="cmnt_cont" id="cmnt_cont_<?php echo $comment_id ?>">
<div class="cmnt_text" id="cmnt_text_<?php echo $comment_id ?>" style="white-space: pre-line">
<p><?php echo $comment ?></p>
</div>
<div class="cmnt_input" id="cmnt_input_<?php echo $comment_id ?>">
<textarea id="cmnt_content_<?php echo $comment_id ?>"><?php echo $comment ?></textarea>
<button type="button" id="btnCmntEdit" data-id="<?php echo $comment_id ?>">수정</button>
</div>
</div>
<div class="cmnt_reply_wr" id="cmnt_reply_wr_<?php echo $comment_id ?>">
<div class="cmnt_input">
<textarea id="cmnt_reply_content_<?php echo $comment_id ?>"></textarea>
<button type="button" id="btnAddCmntReply" data-id="<?php echo $comment_id ?>">등록</button>
</div>
</div>
<?php echo getSubCommentList($comment_id, $write_table); ?>
</li>
<?php
}
?>
위 구문에서 호출하는 함수 부분
function getSubCommentList($comment_id, $table_nm) {
$sql = "SELECT * FROM {$table_nm} WHERE wr_parent = '$comment_id' AND wr_is_comment = '1' ORDER BY wr_id";
//$sql = "SELECT wr_name, wr_datetime, mb_id, wr_nogood, wr_content, wr_comment_reply FROM {$table_nm} WHERE wr_is_comment = '1' AND wr_parent = '$comment_id' ORDER BY wr_id";
// echo $sql."<br>";
$result = sql_query($sql);
$strHtml = '';
if (sql_num_rows($result) > 0) {
$strHtml = '<ul class="reply_list">';
for ($i=0;$row=sql_fetch_array($result);$i++) {
$strHtml .= '
<li>
<div class="info">
<span>'.$row['wr_name'].'</span>
<div class="date">
<i>'.date('Y-m-d', strtotime($row['wr_datetime'])).'</i>
<i>'.date('H:i:s', strtotime($row['wr_datetime'])).'</i>
</div>
<div class="modify">';
if ($user['mb_id'] == $row['mb_id']) {
$strHtml .= ' <button type="button" class="btn_edit" data-key="' . $row['wr_id'] . '"><span class="blind">수정</span></button>
<button type="button" class="btn_remove" data-key="' . $row['wr_id'] . '"><span class="blind">삭제</span></button>';
}
$strHtml .= ' </div>
<div class="util">
<button type="button" class="btn_c_report" data-key="'.$row['wr_id'].'">신고 '.number_format($row['wr_nogood']).'</button>
<button type="button" class="btn_reply" data-key="'.$row['wr_id'].'">답글</button>
<button type="button" class="btn_reply_cancel" data-key="'.$row['wr_id'].'">취소</button>
</div>
</div>
<div class="cmnt_cont" id="cmnt_cont_'.$row['wr_id'].'">
<div class="cmnt_text" id="cmnt_text_'.$row['wr_id'].'">
<p>'.$row['wr_content'].'</p>
</div>
<div class="cmnt_input" id="cmnt_cont_'.$row['wr_id'].'">
<textarea id="cmnt_content_'.$row['wr_id'].'">'.$row['wr_content'].'</textarea>
<button type="button" id="btnCmntEdit" data-id="'.$row['wr_id'].'">수정</button>
</div>
</div>
<div class="cmnt_reply_wr" id="cmnt_reply_wr_'.$row['wr_id'].'">
<div class="cmnt_input" id="cmnt_input_'.$row['wr_id'].'">
<textarea id="cmnt_reply_content_'.$row['wr_id'].'"></textarea>
<button type="button" id="btnAddCmntReply" data-id="'.$row['wr_id'].'">등록</button>
</div>
</div>';
$strHtml .= getSubCommentList($row['wr_id'], $table_nm);
$strHtml .= ' </li>';
}
$strHtml .= '</ul>';
}
return $strHtml;
}
답변 2
인덱스를 살펴 보면
show index from g5_write_free ;
+------------------+------------+---------------------+--------------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name |
+------------------+------------+---------------------+--------------+---------------+
| g5575_write_free | 0 | PRIMARY | 1 | wr_id |
| g5575_write_free | 1 | wr_seo_title | 1 | wr_seo_title |
| g5575_write_free | 1 | wr_num_reply_parent | 1 | wr_num |
| g5575_write_free | 1 | wr_num_reply_parent | 2 | wr_reply |
| g5575_write_free | 1 | wr_num_reply_parent | 3 | wr_parent |
| g5575_write_free | 1 | wr_is_comment | 1 | wr_is_comment |
| g5575_write_free | 1 | wr_is_comment | 2 | wr_id |
+------------------+------------+---------------------+--------------+---------------+
7 rows in set (0.00 sec)
wr_parent와 wr_is_comment 조합은 인덱스 사용을 안 하것으로 보입니다.
wr_num을 추가해 보세요.
재귀호출은 아닙니다.
쿼리1은 이미 실행 종료된 상태이고
skin 쪽에서의 반복문은 쿼리2만 반복 실행합니다.
쿼리1 의 할당 리소스를 먼저 해제하고 싶다면
skin 쪽에서 가장 윗 라인에 다음처럼 시도해 볼수 있습니다.
sql_free_result($result)
다만 현재 DB 부하에 직접적인 큰 연관성은 없을것 같습니다.
쿼리1, 쿼리2 모두 Limit 절. 페이징이 없습니다.
각 쿼리의 result rows 가 과도하게 나오는 경우라면 페이징이 필요한 상황일수 있습니다.
추가적으로 적절한 솔루션이 될지는 모르겠지만
INNER JOIN 을 이용한 한번의 쿼리로 가져오는 방법도 있을것 같습니다.
!-->