首先要注意的是,您实际上并不需要缓存 count(*) 查询的结果。
虽然不同的 RDBMS 处理计数操作的方式不同,但对于大型表来说,它们的速度很慢。但它们的一个共同点是,RDBMS 提供了 SELECT COUNT(*) 的替代方法,它实际上是一个缓存结果。好吧。
你还没有提到你的 RDBMS 是什么,所以让我们看看它在 Django 使用的流行的 RDBMS 中是怎样的
mysql
假设您的表上有一个主键并且您正在使用 MyISAM。 SELECT COUNT() 在 mysql 上速度非常快,并且可以很好地扩展。但很有可能你正在使用 Innodb。出于各种原因,这是正确的存储引擎。 Innodb 是事务感知的,不能像 MyISAM 一样处理 COUNT() 并且查询会随着表的增长而变慢。
对有 2M 条记录的表的计数查询耗时 0.2317 秒。以下查询耗时 0.0015 秒
SELECT table_rows FROM information_schema.tables
WHERE table_name='for_count';
但它报告的值是 1997289 而不是 200 万,但足够接近!
因此您不需要自己的缓存系统。
Sqlite
Sqlite COUNT(*) 查询并不是很慢,但也无法扩展。随着表大小的增长,计数查询的速度变慢。使用类似于 mysql 中使用的表,SELECT COUNT(*) FROM for_count 需要 0.042 秒才能完成。
没有捷径可走。 sqlite_master 表不提供行数。 pragma table_info也没有
你需要自己的系统来缓存SELECT COUNT(*)的结果
Postgresql
尽管是功能最丰富的开源 RDBMS,但 postgresql 不擅长处理 count(*),它很慢并且不能很好地扩展。也就是说,跟穷亲戚没什么区别!
在 postgreql 上计数查询耗时 0.194 秒。另一方面,以下查询耗时 0.003 秒。
SELECT reltuples FROM pg_class WHERE relname = 'for_count'
您不需要自己的缓存系统。
SQL 服务器
SQL 服务器上的 COUNT 查询平均耗时 0.160 秒,但波动相当大。对于这里讨论的所有数据库,第一个 count(*) 查询相当慢,但随后的查询更快,因为该文件已被操作系统缓存。
我不是 SQL Server 方面的专家,所以在回答这个问题之前,我不知道如何使用架构信息来查找行数。我发现这个Q&A 很有帮助。我试过的其中一个在 0.004 秒内产生了结果
SELECT t.name, s.row_count from sys.tables t
JOIN sys.dm_db_partition_stats s
ON t.object_id = s.object_id
AND t.type_desc = 'USER_TABLE'
AND t.name ='for_count'
AND s.index_id = 1
您不需要自己的缓存系统。
集成到 Django
可以看出,除了 sqlite 之外的所有数据库都提供了内置的“缓存查询计数”,我们不需要自己创建一个。创建一个客户经理来使用此功能是一件简单的事情。
class CustomManager(models.Manager):
def quick_count(self):
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("""SELECT table_rows FROM information_schema.tables
WHERE table_name='for_count'""")
row = cursor.fetchone()
return row[0]
class Sample(models.Model):
....
objects = CustomManager()
上面的例子是针对 postgresql 的,但同样的事情也可以用于 mysql 或 sql server,只需将查询更改为上面列出的查询之一。
普罗米修斯
如何将其插入 django prometheus?我把它留作练习。