можно ли кэшировать таблицу в sqlalchemy, чтобы не запрашивать базу данных в конкретном случае использования?

#python #sqlalchemy

#питон #sqlalchemy

Вопрос:

У меня есть пример использования, когда я запускаю скрипт python, постоянно обновляющий определенный столбец в таблице базы данных. Сценарий выглядит следующим образом:

 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()  

Моя проблема в том, что каждый цикл занимает гораздо больше времени, чем это допустимо, потому что я обновляю 100 тысяч событий. Я хочу реализовать какой-то моментальный снимок или кэш в начале каждого цикла, чтобы каждый запрос на SportEvent самом деле не создавал запрос к базе данных, а просто проверял кэш. (Я понимаю риски этого, и они приемлемы для моего варианта использования в том, как эта таблица обновляется/доступна в целом). Как я могу реализовать что-то подобное?

 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 = ""  

Комментарии:

1. Сколько всего команд?

2. команды @flakes являются

3. Можете ли вы также опубликовать класс таблицы для SportEvent ? Нужно увидеть тип в столбцах

4. Каков номинальный случай при обновлении идентификатора события? Какой процент идентификаторов событий обычно обновляется из 100 тысяч?

5. @flakes Обновлено, чтобы включить SportEvent я также включил дополнительный фильтр даты и времени, который я использую (изначально оставил его, чтобы упростить свой вопрос, но так как это повлияет на производительность запроса, я добавил его обратно)

Ответ №1:

Итак, то, что вы здесь испытываете, — это стоимость поездки туда и обратно из вашего сервиса в вашу базу данных. В зависимости от того, сколько записей необходимо вернуть, существует несколько вариантов.

Обратите внимание, что без более глубокого понимания предоставленных данных эти запросы могут быть неоптимальными.

Самый очевидный из них-выполнение массовых запросов. Скажите, что время обновлений примерно в одно и то же время. Мы могли бы сделать что-то вроде этого:

 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 lt; begin:  begin = gametime  if not end or gametime gt; 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 lt; record.game_time lt; 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, что ниже ваших общих требований к запросу.