-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix slow query caused by GET /articles #414
Conversation
9646dab
to
8c336ad
Compare
8c336ad
to
062c39d
Compare
indexes = [ | ||
models.Index( | ||
fields=["created_at", "parent_board_id"], | ||
name="created_at_parent_board_id_idx", | ||
) | ||
] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Composite index of (created_at, parent_board_id) is needed
MySQL order by
optimization doc
In this query, key_part1 is constant, so all rows accessed through the index are in key_part2 order, and an index on (key_part1, key_part2) avoids sorting if the WHERE clause is selective enough to make an index range scan cheaper than a table scan:
SELECT * FROM t1
WHERE key_part1 = constant
ORDER BY key_part2;
count = ( | ||
queryset.count() | ||
- queryset.filter( | ||
created_by__id__in=self.request.user.block_set.values("user"), | ||
name_type=NameType.ANONYMOUS, | ||
).count() | ||
) | ||
|
||
# exclude article written by blocked users in anonymous board | ||
queryset = queryset.exclude( | ||
created_by__id__in=self.request.user.block_set.values("user"), | ||
name_type=NameType.ANONYMOUS, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocked user filtering을 한 번만 하게 바꾸는 게 어떤가요?
count = ( | |
queryset.count() | |
- queryset.filter( | |
created_by__id__in=self.request.user.block_set.values("user"), | |
name_type=NameType.ANONYMOUS, | |
).count() | |
) | |
# exclude article written by blocked users in anonymous board | |
queryset = queryset.exclude( | |
created_by__id__in=self.request.user.block_set.values("user"), | |
name_type=NameType.ANONYMOUS, | |
) | |
# exclude article written by blocked users in anonymous board | |
queryset = queryset.exclude( | |
created_by__id__in=self.request.user.block_set.values("user"), | |
name_type=NameType.ANONYMOUS, | |
) | |
count = queryset.count() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- count = queryset.count() 로 하면 현재와 동일한 쿼리를 사용하게 됨 (다음 문제의 쿼리)
SELECT COUNT(*) AS `__count`
FROM `core_article`
WHERE (
`core_article`.`deleted_at` = '0001-01-01 00:00:00.000000' AND NOT (`core_article`.`created_by_id` IN (
SELECT U0.`user_id`
FROM `core_block` U0
WHERE (
U0.`deleted_at` = '0001-01-01 00:00:00.000000' AND U0.`blocked_by_id` = %s
)
) AND `core_article`.`name_type` = %s)
)
- 위 쿼리가 느린 이유는 NOT IN 절로 예상됨
- 위 쿼리를 유지한 상태에서 속도를 개선하는 방법은 찾지 못했으며, 코드상의 쿼리처럼 둘로 나누어 처리하면 쿼리가 Slow Query로 잡히지 않을 정도로 빨라지는 것을 확인함
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Mitigate two slow queries reported from sentry
Add composite index for core_article.(created_at, parent_board_id) to avoid full scan due to order by from following slow query:
COUNT
query for pagination.Query after optimization consists of two parts to not use
NOT IN
statement: