首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在SQLAlchemy中映射大量相似的表

在SQLAlchemy中映射大量相似的表
EN

Stack Overflow用户
提问于 2014-03-28 04:51:53
回答 3查看 5.5K关注 0票数 9

我有许多(~2000)个具有时间序列数据的位置。每个时间序列都有数百万行。我想将这些存储在Postgres数据库中。我目前的方法是为每个位置时间序列创建一个表,并使用一个元表来存储每个位置的信息(坐标、高程等)。我使用Python/SQLAlchemy来创建和填充表。我想要在元表和每个时间序列表之间建立一个关系,以便执行类似“选择日期A和日期B之间的数据的所有位置”和“选择日期A的所有数据并导出带有坐标的csv”的查询。创建具有相同结构(只是名称不同)的多个表并与元表建立关系的最佳方法是什么?或者我应该使用不同的数据库设计?

目前,我正在使用这种方法来生成许多类似的映射:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from sqlalchemy import create_engine, MetaData
from sqlalchemy.types import Float, String, DateTime, Integer
from sqlalchemy import Column, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref

Base = declarative_base()


def make_timeseries(name):
    class TimeSeries(Base):

        __tablename__ = name
        table_name = Column(String(50), ForeignKey('locations.table_name'))
        datetime = Column(DateTime, primary_key=True)
        value = Column(Float)

        location = relationship('Location', backref=backref('timeseries',
                                lazy='dynamic'))

        def __init__(self, table_name, datetime, value):
            self.table_name = table_name
            self.datetime = datetime
            self.value = value

        def __repr__(self):
            return "{}: {}".format(self.datetime, self.value)

    return TimeSeries


class Location(Base):

    __tablename__ = 'locations'
    id = Column(Integer, primary_key=True)
    table_name = Column(String(50), unique=True)
    lon = Column(Float)
    lat = Column(Float)

if __name__ == '__main__':
    connection_string = 'postgresql://user:pw@localhost/location_test'
    engine = create_engine(connection_string)
    metadata = MetaData(bind=engine)
    Session = sessionmaker(bind=engine)
    session = Session()

    TS1 = make_timeseries('ts1')
    # TS2 = make_timeseries('ts2')   # this breaks because of the foreign key
    Base.metadata.create_all(engine)
    session.add(TS1("ts1", "2001-01-01", 999))
    session.add(TS1("ts1", "2001-01-02", -555))

    qs = session.query(Location).first()
    print qs.timeseries.all()

这种方法有一些问题,最明显的是,如果我创建了多个TimeSeries,那么外键就不起作用。之前我已经使用了一些变通方法,但这一切看起来都像是一个大麻烦,我觉得肯定有更好的方法来做这件事。我应该如何组织和访问我的数据?

EN

回答 3

Stack Overflow用户

发布于 2014-04-03 00:31:32

Alternative-1: Table Partitioning

当我读到完全相同的表结构时,我立刻想到了Partitioning。我不是数据库管理员,使用它的生产经验也不多(在PostgreSQL上更是如此),但请阅读PostgreSQL - Partitioning文档。表分区旨在解决您的问题,但超过1000个表/分区听起来很有挑战性;因此,请在论坛/SO上进行更多研究,以了解与可伸缩性相关的问题。

考虑到这两个最常用的搜索标准,datetime组件是非常重要的,因此必须有可靠的索引策略。如果您决定使用partitioning根目录,那么显而易见的分区策略将基于日期范围。与最近的数据相比,这可能允许您将旧数据划分为不同的块,特别是假设旧数据(几乎从不)更新,因此物理布局将是密集和有效的;而您可以对更“新”的数据采用另一种策略。

Alternative-2: trick SQLAlchemy

这基本上是通过欺骗SA来假设所有这些TimeSeries都是使用Concrete Table Inheritance的一个实体的children,从而使您的示例代码工作。下面的代码是自包含的,它创建了50个表,其中包含最少的数据。但是如果你已经有了一个数据库,它应该允许你相当快地检查性能,这样你就可以做出决定,如果它甚至是接近的可能性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from datetime import date, datetime

from sqlalchemy import create_engine, Column, String, Integer, DateTime, Float, ForeignKey, func
from sqlalchemy.orm import sessionmaker, relationship, configure_mappers, joinedload
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.ext.declarative import AbstractConcreteBase, ConcreteBase


engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base(engine)


# MODEL
class Location(Base):
    __tablename__ = 'locations'
    id = Column(Integer, primary_key=True)
    table_name = Column(String(50), unique=True)
    lon = Column(Float)
    lat = Column(Float)


class TSBase(AbstractConcreteBase, Base):
    @declared_attr
    def table_name(cls):
        return Column(String(50), ForeignKey('locations.table_name'))


def make_timeseries(name):
    class TimeSeries(TSBase):
        __tablename__ = name
        __mapper_args__ = { 'polymorphic_identity': name, 'concrete':True}

        datetime = Column(DateTime, primary_key=True)
        value = Column(Float)

        def __init__(self, datetime, value, table_name=name ):
            self.table_name = table_name
            self.datetime = datetime
            self.value = value

    return TimeSeries


def _test_model():
    _NUM = 50
    # 0. generate classes for all tables
    TS_list = [make_timeseries('ts{}'.format(1+i)) for i in range(_NUM)]
    TS1, TS2, TS3 = TS_list[:3] # just to have some named ones
    Base.metadata.create_all()
    print('-'*80)

    # 1. configure mappers
    configure_mappers()

    # 2. define relationship
    Location.timeseries = relationship(TSBase, lazy="dynamic")
    print('-'*80)

    # 3. add some test data
    session.add_all([Location(table_name='ts{}'.format(1+i), lat=5+i, lon=1+i*2)
        for i in range(_NUM)])
    session.commit()
    print('-'*80)

    session.add(TS1(datetime(2001,1,1,3), 999))
    session.add(TS1(datetime(2001,1,2,2), 1))
    session.add(TS2(datetime(2001,1,2,8), 33))
    session.add(TS2(datetime(2002,1,2,18,50), -555))
    session.add(TS3(datetime(2005,1,3,3,33), 8))
    session.commit()


    # Query-1: get all timeseries of one Location
    #qs = session.query(Location).first()
    qs = session.query(Location).filter(Location.table_name == "ts1").first()
    print(qs)
    print(qs.timeseries.all())
    assert 2 == len(qs.timeseries.all())
    print('-'*80)


    # Query-2: select all location with data between date-A and date-B
    dateA, dateB = date(2001,1,1), date(2003,12,31)
    qs = (session.query(Location)
            .join(TSBase, Location.timeseries)
            .filter(TSBase.datetime >= dateA)
            .filter(TSBase.datetime <= dateB)
            ).all()
    print(qs)
    assert 2 == len(qs)
    print('-'*80)


    # Query-3: select all data (including coordinates) for date A
    dateA = date(2001,1,1)
    qs = (session.query(Location.lat, Location.lon, TSBase.datetime, TSBase.value)
            .join(TSBase, Location.timeseries)
            .filter(func.date(TSBase.datetime) == dateA)
            ).all()
    print(qs)
    # @note: qs is list of tuples; easy export to CSV
    assert 1 == len(qs)
    print('-'*80)


if __name__ == '__main__':
    _test_model()

Alternative-3: a-la BigData

如果您在使用数据库时遇到性能问题,我可能会尝试:

  • 仍然将数据保存在单独的表/数据库/模式中,就像您使用数据库引擎
  • 提供的“原生”解决方案来处理MapReduce-like数据一样使用MapReduce-like分析。在这里,我会继续使用和
    • ,并实现自己的分布式查询和聚合(或者找到一些已存在的东西)。显然,只有当您不需要直接在database.

上生成这些结果时,这种方法才有效

编辑-1:Alternative-4: TimeSeries databases

我没有大规模使用它们的经验,但绝对是一个值得考虑的选择。

如果你以后能分享你的发现和整个决策过程,那就太好了。

票数 12
EN

Stack Overflow用户

发布于 2014-03-31 16:51:01

我会避免你上面提到的数据库设计。我对您正在处理的数据知之甚少,但听起来您应该有两个表。一个表用于location,一个子表用于location_data。location表将存储您上面提到的数据,如坐标和高程。location_data表将存储来自location表的location_id以及您想要跟踪的时间序列数据。

这将避免每次添加另一个位置时更改数据库结构和代码更改,并允许执行您正在查看的查询类型。

票数 3
EN

Stack Overflow用户

发布于 2014-03-31 16:59:13

两部分:

只使用两张表

没有必要有几十个或数百个相同的表。只需为locationlocation_data创建一个表,其中每个条目都将fkey到位置。还可以在location_id的location_data表上创建一个索引,这样就可以进行高效的搜索。

不要使用sqlalchemy来创建它

我喜欢sqlalchemy。我每天都在用它。它对于管理您的数据库和添加一些行非常有用,但是您不希望将其用于具有数百万行的初始设置。您希望生成一个与postgres的" COPY“语句兼容的文件[ http://www.postgresql.org/docs/9.2/static/sql-copy.html ]COPY可以让您快速获取大量数据;它是在转储/恢复操作期间使用的。

sqlalchemy对于查询和添加进来的行来说将是很棒的。如果有批量操作,则应使用COPY。

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

https://stackoverflow.com/questions/22704470

复制
相关文章
当我们谈论Monad的时候(二)
在上一篇文章中,我通过几个Java的例子简单的说明了Monad的本质和一些工程中常见的用途。接下来的文章就不再侧重于工程了,而是要慢慢向理论转换。而作为过渡,我选择了Haskell来代替Java进行说明。本篇文章默认读者已经对Haskell的基本语法有所了解,因此对此类内容我不会再做赘述。
KAAAsS
2022/01/14
8170
当我们谈论Monad的时候(一)
坊间一直流传着一句话:“一百个学FP的人的心中就有一百个对Monad的理解”。而我相信,他们中的大部分人在看明白后又会写出一篇崭新的Monad文。我也一直很想写一写自己关于Monad的见解,但是一直找不到合适的说明方式。先前我在某群提到,从Optional(也就是Haskell的Maybe)理解Monad会是一个很不错的方式。而直到最近我正好看到了这样一篇文章(Reference 1),与我的想法不谋而合,于是我就借用这篇文章的方式谈一谈我对Monad的理解吧。
KAAAsS
2022/01/14
4470
当我参加培训的时候,我在学什么?
在旧金山举行的 erlang/elixir 2017 大会上周结束。这次,我并未参加 —— 权衡再三,我选择了这周的 complete OTP 培训,毕竟大会的视频 youtube 上找得见,可以慢慢补,培训错过了就没了。 参加一次技术培训,代价往往不菲,像这样一个四天的培训,价格是两千多刀,你很难说出它有多值 —— 培训的主题有一半都是我已经了解或掌握的内容,在过去的一两个月,我还给我的 team 培训过;另一半,其实给我空出来四天的时间,我自己看书或者读 erlang 的文档,获取到的知识也未必比参加培
tyrchen
2018/03/29
7120
当我参加培训的时候,我在学什么?
当我们在谈 SaaS 的时候,在谈什么?
SaaS(software as a service),软件即服务,是一种软件交付和销售方式——订阅许可模式。
人称T客
2020/09/08
9110
当我们在谈 SaaS 的时候,在谈什么?
当我在微调的时候我在微调什么?
从 BERT 开始,预训练模型(PLMs)+微调(finetune)已经成为了NLP领域的常规范式。通过引入额外的参数(新的网络层)和特定任务的目标函数,PLMs在该任务的数据集下经过finetune后,总能取得评价指标上的提升,甚至达到SOTA。
对白
2022/04/01
1.7K0
当我在微调的时候我在微调什么?
当我们谈「面试」的时候,我们在谈些什么
关于作者:我是Jing,茶水间非资深潜水员,一个快3岁的数据分析师;爱数据分析爱读书爱海贼,欢迎一起交流探讨~
木东居士
2019/07/17
4330
当我们谈「面试」的时候,我们在谈些什么
当我们讨论swoole的时候,我们在讨论什么?
首先,我们需要肯定的是,它的出现是为了弥补php更准确的是laravel的短板:性能和资源利用率。其次,就我们现有的场景来说,更多的是开发http的相关功能。
槽痞
2020/12/03
5.9K0
当我们讨论swoole的时候,我们在讨论什么?
当我们谈“业务”的时候,我们在谈些什么
关于作者:Japson。某人工智能公司AI平台研发工程师,专注于AI工程化及场景落地。持续学习中,期望与大家多多交流技术以及职业规划。
Python数据科学
2019/07/31
6200
当我看技术文章的时候,我在想什么?
一个叫做“绝色天龙”的小伙伴写于 2018 年 7 月,总阅读 12w 多还挺高的。
why技术
2021/04/22
3840
当我看技术文章的时候,我在想什么?
当我们在谈论vim的时候我们在谈什么
最近我想开一个新的系列,记录我使用vim的相关心得。初次接触vim是在大学操作系统实践课程中,跟着Linux一块进行学习的。当初我是百般嫌弃它的,想要进行编辑还要按下其他键,我想要移动光标居然还的切换到普通模式下,这些种种我一直认为是反人类的。后来经过无数次的尝试、放弃、再尝试的过程,如今我已经离不开它了,不管用何种编辑器、用何种IDE,我首先会找是否有相关的vim模拟插件。这个文章标题也是我使用vim的心路历程,我采用这个标题,也是希望我写出来的文章,能给我的读者带来一些帮助,使各位读者也能像我一样从恶语相向到爱不释手。
Masimaro
2022/05/10
4440
当我们谈论生信的时候我们在谈什么
作为进化研究的重要手段,生物信息学担当了越来越重要的作用。作为一个极难进行实验重复和验证的学科,只能尝试根据现有的东西推断上百万及千万年前的历史。同时,生物信息学依然受到很多的质疑,且不为很多生物研究者所理解。这也是由于其是新兴的交叉学科(统计学,计算机科学与生物学)的特性所决定的。
生信宝典
2019/10/10
1.3K0
当我们谈论生信的时候我们在谈什么
当我们在看Etherscan的时候,到底在看什么?
伴随上周爱死机的NFT事件,WEB3的世界里基建(与用户认知)严重薄弱的缺点,俨然成了众多爱好者想要深入的阻碍(实在被mint后NFT在哪里问烦了)。
十四君
2023/02/18
8840
当我们在看Etherscan的时候,到底在看什么?
当我们说正交化的时候,我们在说些什么
这篇没有新的内容,只是把一个老的掉牙的东西,想的更清楚一些。关于正交化,很早之前写过一篇《因子正交化》,细节可以参考这篇,不再展开。
量化小白
2023/03/19
6200
当我们说正交化的时候,我们在说些什么
当我们遇到问题的时候改如何解决
问题 在Openlayer3中直接加载PNG图片,在API中提供了ImageStatic可以将图片展示出来,但是如何设置图片的imageExtent让图片能够在地图的正确位置展示成了问题的关键。
牛老师讲GIS
2018/10/23
1.1K0
当我们遇到问题的时候改如何解决
当我们说数据挖掘的时候我们在说什么
现在市面上谈论到的数据挖掘基本上都是基于统计学习的监督学习或非监督学习问题。尤其以监督学习应用面更广。
IT阅读排行榜
2018/08/16
3290
当我们在谈论瑞幸咖啡的时候,我们谈论什么?
一个成立48年的咖啡巨头竟然被问到是否有可能被一个乳臭未干的新入局者超越,年初,路透社记者的这个提问让星巴克的CEO始料不及。但是瑞幸咖啡的破坏性创新更是让这家咖啡巨头措手不及,给了它重重的一拳,中国咖啡市场的格局也正因此被改变。
曾响铃
2019/04/25
8480
当我们在谈论瑞幸咖啡的时候,我们谈论什么?
(视频)当我们说Spring IoC的时候,我们在说些什么?
其实,想看好Spring的源码,理解Spring中的很多概念非常重要,而这些概念呢,在Spring的官方文档上面是解释最全面的,所以看源码之前我们一定要先理解Spring的概念,这样才能做到游刃有余,才能看懂大部分的源码。
彤哥
2020/02/19
3070
IDEA修改的文件commit的时候没有提示
情况: 我一个IDEA窗口打开了很多个项目,其他项目修改了文件commit的时候都有提示,但是有一个项目无论修改了什么文件commit的时候都没有提示。
HaC
2020/12/30
2.9K0
IDEA修改的文件commit的时候没有提示
当我们在谈论 memory order 的时候,我们在谈论什么
该文介绍了如何利用C++ 11新特性在程序中引入memory order,从而确保数据在多线程环境中正确性和性能。作者详细介绍了memory order的概念以及C++ 11中提供的两种memory order:memory_order_seq_cst和memory_order_acquire。文章还讨论了在多线程环境中出现的一些问题,例如:memory fence、memory barrier、relaxed memory order等,并给出了示例代码以说明如何使用C++ 11的新特性来避免这些问题。
serena
2017/09/12
4.1K4
当我们在谈论 memory order 的时候,我们在谈论什么
当我们在谈论高并发的时候究竟在谈什么?
高并发是互联网分布式系统架构的性能指标之一,它通常是指单位时间内系统能够同时处理的请求数,简单点说,就是QPS(Queries per second)。
Java团长
2019/07/11
4720
当我们在谈论高并发的时候究竟在谈什么?

相似问题

PowerBI切片器过滤其他切片器

110

PowerBI“包含”切片器

16

无法将值传递给DocuS传模板

14

PowerBI中的时间切片器

120

PowerBI周期切片器(QTD/YTD)

19
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文