首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django存储数据库中的联合表,并在表更改时进行更新

Django存储数据库中的联合表,并在表更改时进行更新
EN

Stack Overflow用户
提问于 2016-06-27 12:03:28
回答 1查看 379关注 0票数 1

在我的Django (1.9)项目中,我需要从昂贵的JOIN构建一个表。因此,我希望将表存储在DB中,并且只在涉及JOIN的表发生变化时重做查询。由于我需要将表作为以后JOIN操作的基础,所以我肯定希望将其存储在数据库中,而不是存储在任何缓存中。我面临的问题是,我不确定如何确定表中的数据是否发生了变化。连接到post_save,相应模型的post_delete信号似乎不正确,因为模型可能通过CSV上传大量更新,而且我不希望每次导入新行时触发昂贵的查询,因为DB表将立即更改。我目前的方法是检查数据是否每隔一段时间就有变化,这对我来说是非常好的。为此,我使用一个新线程,它比较涉及的表的校验和(请参阅下面的代码)来运行此任务。由于我不太熟悉多线程,尤其是在web服务器上,我现在还不熟悉,这是否可以接受。因此,我的问题是:

  1. 运行这个单一任务的线程方法可以接受吗?
  2. 芹菜这样的分布式任务队列是否更合适?
  3. 在接收到信号后,是否有任何方法将信号断开一段时间,以便大容量上传不会一次又一次触发信号?

这是我目前的代码:

代码语言:javascript
复制
import threading
from django.apps import apps
from .models import SomeModel

    def check_for_table_change():

        app_label = SomeModel._meta.app_label

        def join():
            """Join the tables and save the resulting table to the DB."""  
            ...

        def get_involved_models(app_label):
            """Get all the models that are involved in the join."""
            ...

        involved_models = get_involved_models(app_label)
        involved_dbtables = tuple(model._meta.db_table for model in involved_models)
        sql = 'CHECKSUM TABLE %s' % ', '.join(involved_dbtables)
        old_checksums = None

        while(True):
            # Get the result of the query as named tuples.
            checksums = from_db(sql, fetch_as='namedtuple') 
            if old_checksums is not None:
                # Compare checksums.
                for pair in zip(checksums, old_checksums):
                    if pair[0].Checksum != pair[1].Checksum:
                        print('db changed, table is rejoined')
                        join()
                        break
            old_checksums = checksums
            time.sleep(60)

    check_tables_thread = threading.Thread()
    check_tables_thread.run = check_for_table_change
    check_tables_thread.start()

我很感谢你的建议。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-27 14:24:57

物化视图和Postgresql

如果您使用postgresql,则可以使用物化视图。因此,您可以基于join创建一个视图,它将几乎像一个真正的表一样存在。这与每次使用视图时都需要执行查询的普通联接非常不同。现在是坏消息。Mysql没有物化视图。

如果您切换到postgresql,您甚至可能会发现物化的竞争毕竟是不需要的。这是因为postgresql在查询中每个表可以使用多个索引。因此,通过更好地使用Postgresql上的索引,您目前在mysql上的连接速度可能会更快。当然,这很大程度上取决于你的结构。

信号与触发器

我面临的问题是,我不确定如何确定表中的数据是否发生了变化。连接到post_save,相应模型的post_delete信号似乎不正确,因为模型可能通过CSV上传大量更新,而且我不希望每次导入新行时触发昂贵的查询,因为DB表将立即更改。

正如您正确地确定的那样,Django信号不是正确的方法。这是最好在数据库级别完成的任务。由于您没有物化视图,所以这是触发器的作业。然而,这需要大量的艰苦工作(无论您使用触发器还是信号)。

运行这个单一任务的线程方法可以接受吗?

为什么不在这里使用django作为CLI呢?这实际上意味着django脚本由cron调用,或者由独立于您的网站的其他机制执行。

像芹菜这样的分布式任务队列是否更合适?

完全是这样的。每次数据更改时,您都可以触发一个执行表更新的任务。

在接收到信号后,是否有任何方法将信号断开一段时间,以便大容量上传不会一次又一次触发信号?

关键字这里是“触发器”:-)

替代方案。

话虽如此,如果您的表增长到几千行,那么进行连接和物理填充表的过程将非常缓慢。这是因为您需要一个详细的查询来确定哪些记录已经更改(除非您为此使用了一个单独的队列)。然后,您需要插入或更新“join表”中的记录--通常update/insert比检索要慢,因此随着数据的大小,这种情况会变得越来越糟。

真正的解决方案可能是优化查询和表。我可以建议您用缓慢的查询发布一个新的问题并共享您的表结构吗?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38053496

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档