#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, что ниже ваших общих требований к запросу.