WebApp/PHP2010. 6. 26. 02:15
데이터베이스를 통해 자료를 사용하다보면, 어떠한 방식으로 자료를 배열에 저장해야 좋을까 고민하게 된다.
데이터베이스를 다루는 프로그램의 진행 구조를 살펴보면, 이러한 고민에 부딪치는 까닭을 알 수 있다.

프로그램은 사용자의 요구에 따라(Input) 데이터베이스에 있는 정보를 꺼내어 배열에 저장하고(Process)
그 값을 화면 구성에 알맞게 적절하게 뿌리도록 프로그램을 작성한다.(Output)

우리는 처리Process 절차 - 데이터베이스에 있는 정보를 변수에 저장하는 단계를 위해서 이를 고민하고 있는 것이다. 그렇다면, 배열 구성 방식에 관한 문제는 어떠한 방법이 출력Output 단계에서 효율적인지만을 확인하면 되는 것이다.

게시판 프로그램을 작성한다는 가정 하에 이 문제를 풀어보도록 하자.
현재 나타나고 있는 게시판은 다음과 같다.
 제목 내용  작성자 
 php입문 php는 <?php로 시작해서 ?>로 끝납니다. php.net
 html입문 html은 <html>로 시작해서 </html>로 끝납니다. w3c.org

이 게시판의 HTML코드는 다음과 같다.
<table>
<tr>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
</tr>
<tr>
<td>php입문</td>
<td>php는 &lt;?php로 시작해서 ?&gt;로 끝납니다.</td>
<td>php.net</td>
</tr>
<tr>
<td>html입문</td>
<td>html은 &lt;html&gt;로 시작해서 &lt;/html&gt;로 끝납니다.</td>
<td>w3c.org</td>
</tr>
</table>
또한 SQL 테이블 구조는 다음과 같다 .
table : `board`
columns: `subject`, `description`, `author`

다음은 위의 내용을 담기 위한 제 1의 배열 방법이다. 위의 표에서 가로축에 해당하는 것을 1차 배열로 놓는 경우이다.
$board => Array
(
[subject] => Array
(
[0] => php입문
[1] => html입문
)
[description] => Array
(
[0] => php는 <?php로 시작해서 ?>로 끝납니다.
[1] => html은 <html>로 시작해서 </html>로 끝납니다.
)
[author] => Array
(
[0] => php.net
[1] => w3c.org
)
)

제 2의 방법은 다음과 같다. 위의 표에서 세로축에 해당되는 것을 1차 배열로 놓는 경우이다.
$board => Array
(
[0] => Array
(
[subject] => php입문
[description] => php는 <?php로 시작해서 ?>로 끝납니다.
[author] => php.net
)
[1] => Array
(
[subject] => html입문
[description] => phtml은 <html>로 시작해서 </html>로 끝납니다.
[author] => w3c.org
)
)

어느것이 효율적인 저장방법일까? 다음의 예제들을 통해서 확인해보자.

첫째는 위의 배열들을 게시물에 뿌리는 방법이다.
제1의 방법을 통한 예제를 먼저 보겠다.
echo "<table>";
echo "<tr>";
echo "<th>제목</th>";
echo "<th>내용</th>";
echo "<th>작성자</th>";
echo "</tr>";
$counter = count($board[subject]);
for($i=0; $i<$counter; $i++) {
echo "<tr>";
echo "<td>".$board[subject][$i]."</td>";
echo "<td>".$board[description][$i]."</td>";
echo "<td>".$board[author][$i]."</td>";
echo "</tr>";
}
echo "</table>";
코드를 보면, 일단 for 반복문의 반복 횟수를 결정하는 문제부터 막힌다.
위에서 제시한 표만 처리하는 코드이기 때문에 여기서는 카운터 횟수를 쉽게 결정했지만,
좀더 유연한 코드를 작성하고자 한다면 처리하기가 매우 어려울 것이다.
한 가지 예를 들자면 다음처럼 몇몇 값이 비어있는 채로 넘어오는 경우이다.
$board => Array
(
[subject] => Array
(
[1] => html입문
)
[description] => Array
(
[0] => php는 <?php로 시작해서 ?>로 끝납니다.
)
[author] => Array
(
[0] => php.net
[1] => w3c.org
)
)
위와 같은 경우는 우리가 원하는 결과를 얻지 못하게 되는 것이다.

그렇다면, 제2의 방법은 어떠할까?
echo "<table>";
echo "<tr>";
echo "<th>제목</th>";
echo "<th>내용</th>";
echo "<th>작성자</th>";
echo "</tr>";
foreach($board as $value) {
echo "<tr>";
echo "<td>".$value[subject]."</td>";
echo "<td>".$value[description]."</td>";
echo "<td>".$value[author]."</td>";
echo "</tr>";
}
echo "</table>";
눈에 띄게 차이가 나지는 않지만, 위의 코드보다 더 간단하다.
반복문의 반복 횟수를 결정하기 위해 고민할 필요도 없이 foreach문만으로도 작성이 가능하다.
또한 제1의 방법과 달리 아래처럼 몇몇 요소가 빠지더라도 반복 횟수에는 문제가 없다.
$board => Array
(
[0] => Array
(
[description] => php는 <?php로 시작해서 ?>로 끝납니다.
[author] => php.net
)
[1] => Array
(
[subject] => html입문
[author] => w3c.org
)
)
얻을 수 있는 것은 이것 뿐만이 아니다. 안의 변수구성도 간단해졌다.
변수에 $i같은 군더더기 요소가 사라짐으로써, 바이트를 좀 더 줄였다.
PHP와 같은 스크립트 프로그램의 경우에는 파일의 용량이 줄어들수록 처리 엔진의 부하가 줄어들기 때문에 더 효과적이다.

둘째는 데이터베이스에서 자료를 꺼내는 것이 아니라 저장하는 경우이다.
제1의 방법을 보자.(execute_query() 함수에 관련해서는 본 블로그에서 검색해보기 바란다.)
$counter = count($board[subject]);
for($i=0; $i<$counter; $i++) {
unset($keys, $values);
foreach($board as $key => $value) {
if($keys==NULL) {
$keys = "`".$key."`";
$values = "'".$value[$i]."'";
} else {
$keys .= ",`".$key."`";
$values .= ",'".$value[$i]."'";
}
}
$query = "INSERT INTO `board` ($keys) VALUES ($values)";
$result = execute_query($query);
}
앞서 말했던 반복 횟수에 대한 비효율이 계속 나타난다.
또 한 가지 주목해야 할 사항은 NULL값에 대한 비효율문제이다.
만약 배열의 값이 다음과 같이 구성이 되어 있다고 하자.
$board => Array
(
[subject] => Array
(
[1] => html입문
)
[description] => Array
(
[0] => php는 <?php로 시작해서 ?>로 끝납니다.
)
[author] => Array
(
[0] => php.net
[1] => w3c.org
)
)
위의 코드와 같은 경우는 다음과 같은 쿼리문을 만들어낼 것이다.
INSERT INTO `board` (`subject`, `description`, `author`) VALUES ('', 'php는 <?php로 시작해서 ?>로 끝납니다.', 'php.net')
INSERT INTO `board` (`subject`, `description`, `author`) VALUES ('html입문', '', 'w3c.org')
이와 같은 쿼리문은 쓸데 없이 NULL값을 데이터베이스에 입력하게 된다.
이에 대한 유일한 대안인 제2의 방법을 살펴보자.
foreach($board as $item) {
unset($keys, $values);
foreach($item as $key => $value) {
if($keys==NULL) {
$keys = "`".$key."`";
$values = "'".$value."'";
} else {
$keys .= ",`".$key."`";
$values .= ",'".$value."'";
}
}
$query = "INSERT INTO `board` ($keys) VALUES ($values)";
$result = execute_query($query);
}
코드는 $i가 빠졌다거나 하는 소소한 차이일 뿐 거의 달라진 것이 없다.
하지만 한 가지 분명한 것은 NULL값 입력과 같은 비효율적 현상은 나타나지 않는다.
만약 배열의 구성이 다음과 같다고 하자.
$board => Array
(
[0] => Array
(
[description] => php는 <?php로 시작해서 ?>로 끝납니다.
[author] => php.net
)
[1] => Array
(
[subject] => html입문
[author] => w3c.org
)
)
이러한 경우 이 코드는 다음과 같은 쿼리문을 만들어 낸다.
INSERT INTO `board` (`description`, `author`) VALUES ('php는 <?php로 시작해서 ?>로 끝납니다.','php.net')
INSERT INTO `board` (`subject`, `author`) VALUES ('html입문','w3c.org')
군더더기 없이 깔끔한 모습이다.

지금까지 더 효율적인 다차원 배열 구성을 찾기 위해 몇 가지 예를 살펴보았다.
for 루프문의 구성이나 그것을 통한 출력물에 있어서, $변수[항목][숫자]의 형태보다 $변수[숫자][항목] 형태의 구성이 더 효율적임을 입증하였다.
앞으로 이러한 배열 형태를 기반으로 하는 많은 알고리즘들을 생겨났으면 한다.
Posted by 마이클