본문으로 바로가기
반응형

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 등 모든 것이 한 번에 설치 가능 합니다.

 

https://laragon.org/

 

Laragon - portable, isolated, fast & powerful universal development environment for PHP, Node.js, Python, Java, Go, Ruby.

Laragon is a fast & powerful local development environment.

laragon.org

 

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 로 가져 오는 속도와 별 차이 없음.

                   그리고 예전 게시물을 수정을 많이 하는 경우가 없음.

 

 

추가 하면 좋을 것 까지 한 다면 서비스단에서 좋은 성능을 낼 것 입니다.

 

 

 

 

 

 

 

 

 

반응형