我在 Postgresql 数据库中有一个不断增长的、可能非常大的表,其中包含来自不同“设备”的不同“通道”的“数据”,例如:
Table data:
id (PK)
device_id (FK -> device)
channel_id (FK -> channel)
timestamp (TIMESTAMP)
value (Float)
Run Code Online (Sandbox Code Playgroud)
我使用分区将表分成多个子表,每个子表对应一个设备,因为我从不需要在同一查询中不同设备的数据。由于并非所有设备都提供所有频道,因此我想获取单个设备的所有可用频道的列表。解决我的问题的一个简单的 SQL 查询是:
SELECT DISTINCT(channel_id) FROM data where device_id = 1;
Run Code Online (Sandbox Code Playgroud)
这工作得很好,但对于数据表中有很多条目的设备来说需要很长时间。使用分区大大加快了这一过程,因为数据库只需检查一个设备的条目,但对于某些设备来说仍然需要很长时间才能完成。
我的应用程序的属性使得为一台设备添加新通道类型的情况很少发生。大多数情况下,设备添加到数据库后频道会很快添加,之后不会再添加新频道。然而,可用通道的数据添加得相当频繁。我还需要经常向用户显示每个设备的可用频道列表,因此希望加快可用频道的查找速度。我已经在channel_ids上有一个索引,希望它能加快获取所需列表的速度,但检索列表仍然需要相当长的时间。
目前,我可以想出几种方法来解决我的问题:
在我看来,第 2 点和第 3 点似乎会增加很多我想避免的不必要的开销。由于我没有找到任何与此主题相关的内容,因此我目前认为解决方案 5. 是我要采用的方法。但是,我想知道是否有人对我的问题有更好的、可能基于数据库的解决方案。
感谢您的帮助。
UPDATE我在 plpgsql 函数中有一条 sql语句。我现在想为每个更新的行调用 pg_notify 函数,并且不确定我的解决方案是否是最佳可能性。
我不知道UPDATE语句本身中有任何位置可以应用该函数。我认为这在该部分中是不可能的SET,如果我在该部分中应用该函数WHERE,它将应用于检查时的每一行,而不仅仅是更新的行,对吗?
因此,我认为我可以使用该RETURNING部分来达到我的目的,并设计了如下功能:
CREATE OR REPLACE FUNCTION function_name() RETURNS VOID AS $BODY$
BEGIN
UPDATE table1
SET a = TRUE
FROM table2
WHERE table1.b = table2.c
AND <more conditions>
RETURNING pg_notify('notification_name', table1.pk);
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE;
Run Code Online (Sandbox Code Playgroud)
不幸的是,这给了我一个错误,说我没有在任何地方使用或存储查询的返回值。因此,我尝试将其放在PERFORM查询前面,但这在语法上似乎不正确。
在尝试了不同的组合后,PERFORM我的最终解决方案是这样的:
CREATE OR REPLACE FUNCTION function_name() RETURNS VOID AS $BODY$
DECLARE
dev_null INTEGER;
BEGIN
WITH updated AS (
UPDATE table1
SET a = TRUE
FROM …Run Code Online (Sandbox Code Playgroud) 我编写了一个模块,根据项目设置中的字典列表(通过导入django.conf.settings)动态添加定期芹菜任务.我这样做是使用一个函数add_tasks来调度一个函数,该函数使用uuid设置中给出的特定函数进行调用:
def add_tasks(celery):
for new_task in settings.NEW_TASKS:
celery.add_periodic_task(
new_task['interval'],
my_task.s(new_task['uuid']),
name='My Task %s' % new_task['uuid'],
)
Run Code Online (Sandbox Code Playgroud)
像这里建议我使用on_after_configure.connect信号来调用我的函数celery.py:
app = Celery('my_app')
@app.on_after_configure.connect
def setup_periodic_tasks(celery, **kwargs):
from add_tasks_module import add_tasks
add_tasks(celery)
Run Code Online (Sandbox Code Playgroud)
这个设置适用于两者celery beat,celery worker但在我用于uwsgi服务我的django应用程序的地方中断了我的设置.Uwsgi运行顺利,直到视图代码第一次使用celery的.delay()方法发送任务.在这一点上,似乎芹菜被初始化,uwsgi但在上面的代码中永远阻止.如果我从命令行手动运行它然后在它阻塞时中断,我得到以下(缩短的)堆栈跟踪:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/kombu/utils/objects.py", line 42, in __get__
return obj.__dict__[self.__name__]
KeyError: 'tasks'
During handling of the above exception, another exception occurred: …Run Code Online (Sandbox Code Playgroud) 我正在尝试将 DateTimeField 添加到我的 django 模型中,并以最大时间戳作为默认值。我已经弄清楚,Django 中的最大时间戳是 9999/12/31 23:59:59,与我的 postgres 数据库中使用的最大时间戳不同。当使用此时间戳作为字段的默认值时,我收到错误OverflowError: date value out of range。因此我尝试使用 9999/01/01 00:00:00 进行相同的操作,如下所示:
start_time = models.DateTimeField(null=False, default=datetime.datetime(9999,01,01,00,00,00,tzinfo=utc))
现在,当我将南迁移应用到数据库时,出现以下异常:
RuntimeWarning: DateTimeField received a naive datetime (9999-01-01 00:00:00) while time zone support is active.
在查看数据库时,我发现我的本地时区已应用于默认值:9999-01-01 00:00:00+01这使我得出结论,django 以某种方式忽略了时区意识,但我不知道为什么会这样。
附加信息:
Django TIME_ZONE 设置为“欧洲/柏林”
USE_TZ 为 True
任何帮助表示赞赏。
django ×2
postgresql ×2
celery ×1
celery-task ×1
celerybeat ×1
database ×1
function ×1
plpgsql ×1
python ×1
set ×1
sql ×1
sql-update ×1
unique ×1