Cacheops나 Cachalot는 장고의 ORM 캐싱을 쉽게 도와주는 패키지이다.
두 패키지가 어떻게 ORM을 캐싱하는지 실습으로 간단하게 사용해보자. 테스트로 사용할 모델은 아래와 같다
class LogMessage(models.Model):
channel_name = models.CharField(max_length=255)
channel_group = models.CharField(max_length=255)
message = models.TextField()
created_at
However, it’s not suited for projects where there is a high number of modifications per second on each table, like a social network with more than a 50 messages per second. Django-cachalot may still give a small speedup in such cases, but it may also slow things a bit (in the worst case scenario, a 20% slowdown, according to the benchmark). If you have a website like that, optimising your SQL database and queries is the number one thing you have to do.
여기서 유의해야할 점은 테이블에 변경사항이 많은 프로젝트에서는 Cachalot이 좋지 않다는 것이다. 그 이유는 실습을 통해서 확인하려고 한다.
설치법은 아래 메뉴얼로 확인
https://django-cachalot.readthedocs.io/en/latest/introduction.html
장고 쉘로 실습
python3 ./manage.py shell_plus --print-sql
In [1]: log3 = LogMessage.objects.get(id=3)
SELECT @@SQL_AUTO_IS_NULL
Execution time: 0.001003s [Database: default]
SET
SESSION
TRANSACTION
ISOLATION LEVEL READ COMMITTED
Execution time: 0.001113s [Database: default]
SELECT `chat_logmessage`.`id`,
`chat_logmessage`.`channel_name`,
`chat_logmessage`.`channel_group`,
`chat_logmessage`.`message`,
`chat_logmessage`.`created_at`
FROM `chat_logmessage`
WHERE `chat_logmessage`.`id` = 3
LIMIT 21
Execution time: 0.000719s [Database: default]
In [2]: log3 = LogMessage.objects.get(id=3)
In [3]:
log3 = LogMessage.objects.get(id=3)
첫 번째로 모델을 get(id=3) 가져올 때 쿼리문이 실행 되었고. 그 다음 다시 get(id=3) 할때는 쿼리문이 실행되지 않았다.
모델을 추가 한 다음 다시 get(id=3) 가져오면 쿼리문이 실행된다.
In [3]: LogMessage.objects.create(channel_name='aaa', channel_group='bb', message='dd')
SELECT VERSION()
Execution time: 0.000732s [Database: default]
INSERT INTO `chat_logmessage` (`channel_name`, `channel_group`, `message`, `created_at`)
VALUES ('aaa', 'bb', 'dd', '2021-05-23 05:24:22.198760')
Execution time: 0.005244s [Database: default]
Out[3]: <LogMessage: LogMessage object (5)>
In [4]: log3 = LogMessage.objects.get(id=3)
SELECT `chat_logmessage`.`id`,
`chat_logmessage`.`channel_name`,
`chat_logmessage`.`channel_group`,
`chat_logmessage`.`message`,
`chat_logmessage`.`created_at`
FROM `chat_logmessage`
WHERE `chat_logmessage`.`id` = 3
LIMIT 21
Execution time: 0.009044s [Database: default]
테이블에 row가 하나 추가가 되었는데 get(id=3)는 다시 쿼리로 질의를 하게 된다. 생각해 보면 id=3인 row가 변경 된 일이 없는데 다시 호출하게 이유는 cachalot는 테이블 단위로 invalidation을 하기 때문이다. 테이블에 어떠한 row가 변경이 되면 그 테이블에 관련된 모든 orm이 invalidation 되기 때문에 테이블에 변경사항이 많은 프로젝트는 적합하지 않다. 대안으로는 row 단위로 ivalidation 하는 cacheops가 있다.
설치법은 아래 메뉴얼로 확인
In [1]: log3 = LogMessage.objects.get(id=3)
SELECT @@SQL_AUTO_IS_NULL
Execution time: 0.000543s [Database: default]
SET
SESSION
TRANSACTION
ISOLATION LEVEL READ COMMITTED
Execution time: 0.000954s [Database: default]
SELECT `chat_logmessage`.`id`,
`chat_logmessage`.`channel_name`,
`chat_logmessage`.`channel_group`,
`chat_logmessage`.`message`,
`chat_logmessage`.`created_at`
FROM `chat_logmessage`
WHERE `chat_logmessage`.`id` = 3
LIMIT 21
Execution time: 0.001151s [Database: default]
In [2]: log3 = LogMessage.objects.get(id=3)
In [3]: LogMessage.objects.create(channel_name='aaa', channel_group='bb', message='dd')
SELECT VERSION()
Execution time: 0.000969s [Database: default]
INSERT INTO `chat_logmessage` (`channel_name`, `channel_group`, `message`, `created_at`)
VALUES ('aaa', 'bb', 'dd', '2021-05-23 05:41:02.460593')
Execution time: 0.002365s [Database: default]
Out[3]: <LogMessage: LogMessage object (6)>
In [4]: log3 = LogMessage.objects.get(id=3)
In [5]:
Cacheops는 row 단위로 invalidation을 하기에 테이블에 row가 추가되도 cachalot처럼 디비에 다시 호출하지 않는다.
반면에 Cacheops 유의해야 할 점은 개발자가 Cacheops 내부 원리를 잘 알고 코딩해야한다 ㅡㅡ;