mysql 데이타베이스에 100 만 로우가 있다고 하면 이걸 서비스 단에다가 붙인다면
기본적인 쿼리는 이렇게 될 것 입니다.
$query = "SELECT * FROM board_test ORDER BY idx desc limit 0,20";
이런 쿼리를 가지고 페이징을 추가 했다면 limit 만 바꾸면서 계속 호출 하는 식이 될 것 입니다.
mysql 특성상 앞 부분에서 가져 오는 부분은 느리지 않을 것 입니다.
하지만 끝 부분으로 갈 수록 페이지 속도가 엄청 느려지는 것을 경험 할 수 있습니다.
이런 경우 에는 모든 mysql 데이타베이스의 row 들을 메모리캐시에 저장 하고 뿌려 준다면 엄청난 시간 단축을 할 수 있습니다.
윈도우를 기준으로 설명 하겠습니다.
저는 윈도우 로컬에 apm 을 설치 할때는 laragon 이라는 것을 설치 해서 사용 합니다.
redis 모듈, memcache 모듈, mysql , mysqladmin, php 등 모든 것이 한 번에 설치 가능 합니다.
exe 형태로 설치 하시면 바로 개발에 들어 갈 수 있습니다.
기본 개념은
1. 백단으로 도는 php 만듭니다.
2. 파일을 1만개당 한 개 씩 만듭니다.
3. 최근 1 만 건 을 loop 로 계속 가져 오는 것 입니다.
제 경험으로 1 만 건 가져 오는 거는 백단으로 돌리는 거는 별 문제 없이 가져 올 수 있었습니다.
이 파일을 계속 해서 돌리면 최근 게시물이 올라오는 것도 대응 할 수 있습니다.
주요 개념을 설명 하자면
mysql 데이타를 가져 와서
redis 의 zadd 를 이용 해서 게시물 번호를 넣습니다.
redis 의 hSet 을 이용 해서 게시판 내용을 넣습니다.
페이징을 할때는
redis 의 zRevRangeByScore 를 이욯 해서 게시물 번호를 가져오고
redis 의 hGet 을 이용 해서 게시판 내용을 가져 와서 뿌려 주면 됩니다.
그럼 소스 코드를 작성 해 보겠습니다.
설치 폴더 C:\laragon\www 로 들어 가셔서 dbredis 라는 폴더를 생성 합니다.
BoardDatabaseRedis.php 라는 파일을 만듭니다.
<?php
const CHUNK_SIZE = 1000;
const NUM_OF_TOP_CHUNK = 100;
const REDIS_KEY_PC = 'pc:';
const REDIS_KEY_POSTS = 'posts:';
$servername = "localhost";
$username = "";
$password = "";
$dbname = "";
// mysql 접속
$conn= mysqli_connect($servername,$username,$password,$dbname);
// 접속 확인
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
//redis 접속
$redis = new Redis();
try {
//redis 접속
$redis->connect('127.0.0.1', '6379', 2.0, null, 150);
} catch (RedisException $e) {
var_dump($e);
exit;
}
//쿼리문
$query = "SELECT idx, firstName as title FROM test_table order by idx desc limit 0,100000";
$resultSet = mysqli_query($conn, $query);
//해당 되는 rows 를 가져 온다.
$dbResults = array();
while ($rows = mysqli_fetch_array($resultSet)) {
$dbResults[] = $rows;
}
//가장 높은 숫자를 가져 온다.
$query = "SELECT MAX(idx) as maxId FROM test_table";
$resultSet = mysqli_query($conn, $query);
$rows = mysqli_fetch_array($resultSet);
$maxId = $rows['maxId'];
//디비 내용을 loop 돌면서 redis 에 넣기
foreach ($dbResults as $dbResult) {
$bbsIdx = $dbResult['idx'];
$bbsTitle = $dbResult['title'];
$score = $dbResult['idx'];
$field = $bbsIdx;
$bbsIdxChunkId = (int) ($bbsIdx / CHUNK_SIZE);
$dbResultJson = json_encode($dbResult);
//zadd 넣기
$redis->zAdd(REDIS_KEY_PC, $score, $bbsIdx);
//hset 하기
$redis->hSet(REDIS_KEY_POSTS. $bbsIdxChunkId, $field, $dbResultJson);
}
//저정하기 끝
// 페이징을 한다는 조건으로 리스트 뽑아 오기
$key = REDIS_KEY_PC;
$totalCount = $redis->zCount($key, '-inf', '+inf');
echo "TotalCount : " . $totalCount;
echo PHP_EOL;
$pageSize = 20;
$page = 1;
$offset = ($page - 1) * $pageSize;
$count = $pageSize;
$options = [];
if ($offset !== null && $count !== null) {
$options['limit'] = [$offset, $count];
}
//해당 하는 게시물 번호들 가져 오기
$postsIds = $redis->zRevRangeByScore($key, '+inf', '-inf', $options);
foreach ($postsIds as $postId) {
$bbsIdxChunkId = (int) ($postId / CHUNK_SIZE);
//게시물 번호에 따른 내용 가져 오기
$posts= $redis->hGet(REDIS_KEY_POSTS . $bbsIdxChunkId, $postId);
$posts = json_decode($posts);
print_r($posts);
}
mysql 데이타베이스 접속 아이디와 패스워드는 직접 넣으시면 됩니다.
위와 같이 한다면 처리 속도가 향상 되는 걸 볼 수 있을 것이다.
shell 상 윈도우 프롬프트 상 에서
php BoardDatabaseRedis.php
라고 명령어를 치면 값들을 볼 수 있습니다.
더 추가 해 보면 좋을 것들
1. 예전 게시물 번호가 게시물이 제목이 수정이 되었을때 어떻게 대처 할지?
2. 이미 있는 게시물 번호는 쓰기 없이 처리 되게 하기?
3. redis 에 저장할 mysql 에서 limit 로 결과 값 가져오지 말고 idx 를 max_no 와 min_no 를 가지고 쿼리문 만들기?
- 단점 : 해당 번호 대역에 데이타가 없어도 돌아서 결과값 없는 쿼리가 돌 수있음
- 장점: 쿼리문 속도가 빨라서 백단에서도 느려질 경우가 없음
3 번을 해결 했다면
4. 100 만건 이라면 최근 10 만개 말고 그 뒤로 90 만건은 어떻게 돌릴지?
- 스크립트를 2 개 만들어서 하나는 최근 것만 돌고 다른 하나는 뒤에 90 만건을 도는 거 만들기
- 단점 : 뒤에꺼가 돌때 시간이 좀 걸려서 반영이 좀 늦게 될 수 있음.
- 장점: 단점이라고 썻지만 쿼리 속도가 엄청 빨라져서 limit 로 가져 오는 속도와 별 차이 없음.
그리고 예전 게시물을 수정을 많이 하는 경우가 없음.
추가 하면 좋을 것 까지 한 다면 서비스단에서 좋은 성능을 낼 것 입니다.
'IT > 언어' 카테고리의 다른 글
php 애플(apple) sns 연동하기 (0) | 2023.06.05 |
---|---|
php 를 이용한 array 활용법 (0) | 2023.06.03 |
firebase 를 이용해서 간단한 소셜 안드로이드 앱 만들어 보기 (4) | 2016.06.01 |
안드로이드 asynctask 정리 (0) | 2016.03.23 |
크롬에서 프레임으로 쌓여진 사이트 뒤로가기 버튼 새로고침 현상 일어 날때. (0) | 2016.03.16 |