带缓存的 Django 模型 count()
Django model count() with caching
我有一个带有 Apache Prometheus 监控和模型的 Django 应用程序,名为 Sample
。
我想监控 Sample.objects.count() 指标
并在具体时间间隔内缓存此值
避免在数据库中进行昂贵的 COUNT(*) 查询。
来自本教程
https://github.com/prometheus/client_python#custom-collectors
我读到我需要编写自定义收集器。
实现此目标的最佳方法是什么?
在 django 中有什么方法可以
获取 Sample.objects.count()
缓存值并在 K 秒后更新它?
我也在我的应用程序中使用 Redis。我应该把这个值存储在那里吗?
我应该创建单独的线程来更新 Sample.objects.count()
缓存值吗?
一个自定义收集器,returns 如果它不是太旧则获取以前的值,否则将是可行的方法。我会将其全部保留在进程中。
如果您使用的是 MySQL,您可能想看看 mysqld_exporter 提供的收集器,因为有一些适合 table 尺寸的收集器应该更便宜。
首先要注意的是,您实际上并不需要缓存 count(*) 查询的结果。
虽然不同的 RDBMS 处理计数操作的方式不同,但对于大型 tables,它们在整体上都很慢。但它们的一个共同点是 RDBMS 提供了 SELECT COUNT(*) 的替代方法,它实际上是一个缓存结果。有点。
您还没有提到您的 RDBMS 是什么,所以让我们看看它在与 Django 一起使用的流行的 RDBMS 中的表现如何
mysql
前提是您的 table 上有一个主键并且您使用的是 MyISAM。 SELECT COUNT() 在 mysql 上非常快并且扩展性很好。但很可能您正在使用 Innodb。由于各种原因,这是正确的存储引擎。 Innodb 是事务感知的,不能处理 COUNT() 和 MyISAM,随着 table 的增长,查询速度变慢。
对具有 2M 记录的 table 的计数查询花费了 0.2317 秒。以下查询耗时 0.0015 秒
SELECT table_rows FROM information_schema.tables
WHERE table_name='for_count';
但它报告的值为 1997289 而不是 200 万,但足够接近了!
所以你不需要自己的缓存系统。
SQLite
Sqlite COUNT(*) 查询并不是真的很慢,但它也不能扩展。随着 table 大小的增长,计数查询的速度会减慢。使用与 mysql 中使用的相似的 table,SELECT COUNT(*) FROM for_count
需要 0.042 秒才能完成。
没有捷径可走。 sqlite_master
table 不提供行数。 pragma table_info
也不行
您需要自己的系统来缓存 SELECT COUNT(*)
的结果
Postgresql
尽管是功能最丰富的开源 RDBMS,postgresql 不擅长处理计数 (*),它速度慢且扩展性不佳。也就是说,跟穷亲没啥区别!
计数查询在 postgreql 上花费了 0.194 秒。另一方面,以下查询花费了 0.003 秒。
SELECT reltuples FROM pg_class WHERE relname = 'for_count'
您不需要自己的缓存系统。
SQL 服务器
SQL 服务器上的 COUNT 查询平均耗时 0.160 秒,但波动相当大。对于此处讨论的所有数据库,第一个 count(*) 查询相当慢,但后续查询速度更快,因为文件已被操作系统缓存。
我不是 SQL 服务器方面的专家,所以在回答这个问题之前,我不知道如何使用架构信息查找行数。我发现这个 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 之外的所有数据库都提供了内置的 'Cached query count' 我们没有必要创建自己的数据库。创建客户经理以利用此功能是一件简单的事情。
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 服务器。
普罗米修斯
如何将其插入 django prometheus?我把它留作练习。
我有一个带有 Apache Prometheus 监控和模型的 Django 应用程序,名为 Sample
。
我想监控 Sample.objects.count() 指标 并在具体时间间隔内缓存此值 避免在数据库中进行昂贵的 COUNT(*) 查询。
来自本教程 https://github.com/prometheus/client_python#custom-collectors 我读到我需要编写自定义收集器。
实现此目标的最佳方法是什么?
在 django 中有什么方法可以
获取 Sample.objects.count()
缓存值并在 K 秒后更新它?
我也在我的应用程序中使用 Redis。我应该把这个值存储在那里吗?
我应该创建单独的线程来更新 Sample.objects.count()
缓存值吗?
一个自定义收集器,returns 如果它不是太旧则获取以前的值,否则将是可行的方法。我会将其全部保留在进程中。
如果您使用的是 MySQL,您可能想看看 mysqld_exporter 提供的收集器,因为有一些适合 table 尺寸的收集器应该更便宜。
首先要注意的是,您实际上并不需要缓存 count(*) 查询的结果。
虽然不同的 RDBMS 处理计数操作的方式不同,但对于大型 tables,它们在整体上都很慢。但它们的一个共同点是 RDBMS 提供了 SELECT COUNT(*) 的替代方法,它实际上是一个缓存结果。有点。
您还没有提到您的 RDBMS 是什么,所以让我们看看它在与 Django 一起使用的流行的 RDBMS 中的表现如何
mysql
前提是您的 table 上有一个主键并且您使用的是 MyISAM。 SELECT COUNT() 在 mysql 上非常快并且扩展性很好。但很可能您正在使用 Innodb。由于各种原因,这是正确的存储引擎。 Innodb 是事务感知的,不能处理 COUNT() 和 MyISAM,随着 table 的增长,查询速度变慢。
对具有 2M 记录的 table 的计数查询花费了 0.2317 秒。以下查询耗时 0.0015 秒
SELECT table_rows FROM information_schema.tables
WHERE table_name='for_count';
但它报告的值为 1997289 而不是 200 万,但足够接近了!
所以你不需要自己的缓存系统。
SQLite
Sqlite COUNT(*) 查询并不是真的很慢,但它也不能扩展。随着 table 大小的增长,计数查询的速度会减慢。使用与 mysql 中使用的相似的 table,SELECT COUNT(*) FROM for_count
需要 0.042 秒才能完成。
没有捷径可走。 sqlite_master
table 不提供行数。 pragma table_info
您需要自己的系统来缓存 SELECT COUNT(*)
的结果Postgresql
尽管是功能最丰富的开源 RDBMS,postgresql 不擅长处理计数 (*),它速度慢且扩展性不佳。也就是说,跟穷亲没啥区别!
计数查询在 postgreql 上花费了 0.194 秒。另一方面,以下查询花费了 0.003 秒。
SELECT reltuples FROM pg_class WHERE relname = 'for_count'
您不需要自己的缓存系统。
SQL 服务器
SQL 服务器上的 COUNT 查询平均耗时 0.160 秒,但波动相当大。对于此处讨论的所有数据库,第一个 count(*) 查询相当慢,但后续查询速度更快,因为文件已被操作系统缓存。
我不是 SQL 服务器方面的专家,所以在回答这个问题之前,我不知道如何使用架构信息查找行数。我发现这个 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 之外的所有数据库都提供了内置的 'Cached query count' 我们没有必要创建自己的数据库。创建客户经理以利用此功能是一件简单的事情。
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 服务器。
普罗米修斯
如何将其插入 django prometheus?我把它留作练习。