可以在 sqlalchemy 中缓存 table 以在特定用例中不查询数据库吗?

possible to cache a table in sqlalchemy to not query database in specific use case?

我有一个用例,我是 运行 一个 python 脚本,不断更新数据库中 table 上的特定列。脚本如下:

while True:
    events = load_events()
    for event in events:
        team_1 = event.team_1
        team_2 = event.team_2
        dd = datetime.strptime(event.gametime, "%Y-%m-%dT%H:%M:%S.000Z")
        begin = dd - timedelta(hours=4)
        end = dd + timedelta(hours=4)

        db_event = session.query(SportEvent).filter(and_(
            SportEvent.home_team.contains(event.team_1),                                      
            SportEvent.away_team.contains(event.team_2),
            SportEvent.game_time.between(begin, end))).first()
        if db_event.e_id != event.event_id:
            setattr(db_event, 'e_id', event.event_id)
    session.commit()

我的问题是每个循环花费的时间比 acceptable 长得多,因为我正在更新 100k 事件。我想在每个循环开始时实现某种快照或缓存,因此对 SportEvent 的每个查询实际上不会对数据库产生查询,而只是检查缓存。 (我理解这样做的风险,并且他们接受 table 对于我的用例来说 table 是如何作为一个整体 updated/accessed 的。我怎样才能实现这样的东西?

class SportEvent(Base):
    __tablename__ = 'sport_events'

    id = Column(String, primary_key=True)
    sport_id = Column(String)
    league_id = Column(String)
    away_team = Column(String)
    home_team = Column(String)
    game_time = Column(DateTime)
    dk_id = Column(String)
    fd_id = Column(String)
    cs_id = Column(String)
    bm_id = Column(String)

    def __init__(self, home_team=None,
                 away_team=None,
                 game_time=None, sport_id=None, league_id=None):
        self.id = uuid.uuid4()
        self.home_team = home_team
        self.away_team = away_team
        self.game_time = game_time
        self.sport_id = sport_id
        self.league_id = league_id
        self.dk_id = ""
        self.fd_id = ""
        self.cs_id = ""
        self.bm_id = ""

所以您在这里遇到的是从您的服务到数据库的每次往返成本。根据需要返回的记录数,有一些选项。

Note, without a deeper understanding of the data provided, these queries might not be optimal.

最明显的一个是批量查询。假设更新时间几乎是同一时间。我们可以这样做:

begin = None
end = None
for event in events:
    gametime = datetime.strptime(event.gametime, "%Y-%m-%dT%H:%M:%S.000Z")
    if not begin or gametime < begin:
        begin = gametime
    if not end or gametime > end:
        end = gametime 
begin = begin - timedelta(hours=4)
end = end + timedelta(hours=4)

records = session.query(SportEvent).filter(
    SportEvent.game_time.between(begin, end)
).all()

现在循环时可以查询已经查询过的数据

for event in events:
    team_1 = event.team_1
    team_2 = event.team_2
    dd = datetime.strptime(event.gametime, "%Y-%m-%dT%H:%M:%S.000Z")
    begin = dd - timedelta(hours=4)
    end = dd + timedelta(hours=4)

    db_event = next(
        (
            record
            for record in records
            if (
                team_1 in record.home_team
                and team_2 in record.away_team
                and begin < record.game_time < end
            )
        ),
        None
    )
    if db_event and db_event.e_id != event.event_id:
        db_event.e_id = event.event_id

session.commit()

同样,更好的答案需要更多地了解事件数据以及如何优化它以限制返回的结果。假设只有特定的球队参加比赛 - 您可以为每支球队进行一次批量查询和一个循环。

基本上您需要查看数据中的共性并尝试尽可能少地调用数据库。

另请注意,大多数数据库对查询中的参数数量都有最大限制,对于 PostgresQL 而言,该限制为 64,000,低于您的总查询要求。