# Postgres 쿼리 1,000배 더 빠르게 만들기

> Clean Markdown view of GeekNews topic #14930. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=14930](https://news.hada.io/topic?id=14930)
- GeekNews Markdown: [https://news.hada.io/topic/14930.md](https://news.hada.io/topic/14930.md)
- Type: news
- Author: [xguru](https://news.hada.io/@xguru)
- Published: 2024-05-22T09:32:02+09:00
- Updated: 2024-05-22T09:32:02+09:00
- Original source: [mattermost.com](https://mattermost.com/blog/making-a-postgres-query-1000-times-faster/)
- Points: 22
- Comments: 3

## Topic Body

- Mattermost는 Elasticsearch를 사용하여 데이터베이스 부하를 줄이고 훨씬 더 빠른 검색 결과를 제공함   
  - Elasticsearch가 제대로 동작하려면 검색 대상이 되는 모든 데이터를 색인해야 함  
  - 이미 색인된 데이터에 대해서는 이후 새 글과 파일의 색인 작업이 꽤 빠름  
  - 그러나, 아주 큰 데이터베이스(1억 개 포스트)를 처음부터 완전히 색인하는 것은 매우 느림(18시간동안 절반도 못하고 점점 느려짐)  
- 데이터베이스 호출 별 소요 시간 그래프를 통해, `PostStore.GetPostsBatchForIndexing` 메서드의 SQL 쿼리가 문제인 것으로 파악됨  
  - 해당 쿼리는 기본적으로 creation timestamp 기준으로 포스트를 정렬하고, 주어진 timestamp보다 새로운 N개의 포스트를 반환함   
  - 이 쿼리를 반복 실행하여 모든 포스트가 색인될 때까지 indexing job이 수행됨  
- `EXPLAIN (ANALYZE, BUFFERS)`를 사용해 쿼리 실행 계획을 분석함:  
  - Posts 테이블에 인덱스 스캔 수행 시 Filter 조건 적용을 위해 4천만 블록을 처리하고 있음 (309GB)  
  - Channels 테이블과의 JOIN은 문제가 아님  
  - WHERE 조건의 OR 절 중 `Posts.CreateAt > ?1` 부분만 적용하면 훨씬 빨라짐 (30ms)  
  - 거기서 `Posts.CreateAt = ?1 AND Posts.Id > ?2` 조건을 적용하면 극도록 빨라짐 (0.047ms)  
- 원인 파악:  
  - 원본 쿼리는 Posts의 모든 행을 훑으면서 Filter로 걸러내는 반면, 수정된 쿼리는 인덱스만 확인하고 필요한 행만 추출함  
  - 시간이 지남에 따라 쿼리가 점점 느려진 이유는 점점 더 많은 행을 걸러내야 했기 때문임  
- 해결책:  
  - PostgreSQL의 row constructor comparison 기능을 활용하여 `(Posts.CreateAt, Posts.Id) > (?1, ?2)` 조건으로 변경  
  - 이렇게 변경한 쿼리는 34밀리초로 실행 시간이 대폭 줄어듦  
  - 그런데 MySQL에서는 변경된 쿼리가 오히려 더 느리게 동작함. MySQL에서는 원본 쿼리가 더 빨랐기에 DB 별로 다른 쿼리 사용하도록 코드 분기 처리함  
- 배운 점들:  
  - `EXPLAIN` 시 `BUFFERS` 옵션을 항상 사용할 것  
  - Filter 대신 Index Cond를 활용하도록 할 것   
  - PostgreSQL과 MySQL은 거의 항상 다르게 동작함을 전제할 것  
- **결론**  
  - 최적화 작업을 통해 쿼리 실행 시간을 1000배 이상 줄이는 성과를 얻음  
  - 이 최적화는 Mattermost v9.7.0 및 v9.5 ESR 버전에 반영됨  
  - 최적화 작업을 통해 많은 것을 배울 수 있었음

## Comments



### Comment 25483

- Author: dontcryme
- Created: 2024-05-23T08:18:15+09:00
- Points: 2

맨 마지막 글에도 있지만 본 글의 제목이 살짝 낚시성느낌이나...좀더 실질적으로 바꿔보자면  
  
'실수를 통해 배운 postgresql 활용 사례'  
  
일까요..

### Comment 25477

- Author: vwjdalsgkv
- Created: 2024-05-23T00:00:42+09:00
- Points: 2

음... 개인적으로 이런 수준의 글을 특정 회사/제품을 걸고 쓴다면, 오히려 그 제품에 대한 신뢰도가 많이 낮아질 것 같습니다.  
정리는 일목요연하지만, 그 안에 담긴 기술적인 가치가 조금 부족해보여 아쉽네요.

### Comment 25480

- Author: savvykang
- Created: 2024-05-23T06:48:54+09:00
- Points: 1
- Parent comment: 25477
- Depth: 1

저도 이 글을 보고나서 오히려 신뢰도가 낮아졌습니다. 돈받고 팔고 있는 제품이 대용량 처리 테스트도 없이 기능을 출시한 거니까요. 저 정도의 간단한 인덱스는 기능 개발 단계에서 설정해야 하는거 아닌가 싶습니다. 소프트웨어 개발 절차가 많이 생략된거 같아 보입니다
