Медленное MySQL время запроса базы данных в цикле Python for - PullRequest
0 голосов
/ 13 марта 2020

У меня есть задача запустить 8 одинаковых запросов (1 запрос на 1 страну) и при этом вернуть данные из базы данных MySQL. Причина, по которой я не могу выполнить 1 запрос со всеми странами в одной, заключается в том, что в каждой стране должны быть разные имена столбцов. Кроме того, результаты должны обновляться ежедневно с динамическим диапазоном дат c (последние 7 дней). Да, я мог бы запустить все страны и сделать именование столбцов и все с Pandas, но я думал, что следующее решение будет более эффективным. Итак, мое решение состояло в том, чтобы создать для l oop, который использует предопределенные списки со всеми странами, их соответствующие измерения и переменные диапазона дат, которые изменяются в соответствии с текущей датой. У меня проблема в том, что запрос MySQL, выполняемый в l oop, занимает намного больше времени, чем если бы я выполнял тот же запрос непосредственно в нашем хранилище данных (~ 140-500 секунд против 30 секунд). Решение работает с меньшими таблицами из DWH. Дело в том, что я не знаю, какая именно часть вызывает проблему и как ее решить.

Вот пример моего кода с некоторыми небольшими «тестами», реализованными в нем:

#Import libraries:
from google.cloud import storage
from google.oauth2 import service_account
import mysql.connector
import pandas as pd
import time
from datetime import timedelta, date

#Create a connection to new DWH:
coon = mysql.connector.connect(
  host="the host goes here",
  user="the user goes here",
  passwd="the password goes here"
)

#Create Google Cloud Service credential references:
credentials = service_account.Credentials.from_service_account_file(r'C:\Users\ivo.vancans\OneDrive\Documents\Python Workspace\my credential json goes here.json')
project_id='my project id goes here'

cursor = coon.cursor()

#Create lists of countries and dimensions
countries = ['EE','FI','LV','LT']
appp_id_dim = ['ga:dimension5','ga:dimension5','ga:dimension5','ga:dimension5']
status_dim = ['ga:dimension21','ga:dimension12','ga:dimension20','ga:dimension15']
score_dim = ['ga:dimension11','ga:dimension11','ga:dimension19','ga:dimension14']

#Define the current date and date that was 7 days before current date:
date_now = date.today() - timedelta(days=1)
date_7d_prev = date_now - timedelta(days=7)

#Create a loop
for c,s in zip(countries, score_dim):
    start_time = time.time()
    #Create the query using string formating:
    query = f"""select ca.ID, sv.subType, SUM(svl.score) as '{s}'
    from aio.CreditApplication ca
    join aio.ScoringResult sr 
    on sr.creditApplication_ID = ca.ID 
    join aio.ScorecardVariableLine svl 
    on svl.id = sr.scorecardVariableLine_ID
    join aio.ScorecardVariable sv 
    on sv.ID = svl.scorecardVariable_ID
    where sv.country='{c}'  
    #and sv.subType ="asc"
    and sv.subType != 'fsc'
    and sr.created >= '2020-01-01'
    and sr.created between '{date_7d_prev} 00:00:00' and '{date_now} 23:59:59'
    group by ca.id,sv.subType"""

    #Check of sql query
    print('query is done', time.time()-start_time)

    start_time = time.time()
    sql = pd.read_sql_query(query, coon)
    #check of assigning sql:
    print ('sql is assigned',time.time()-start_time)

    start_time = time.time()
    df = pd.DataFrame(sql
                      #, columns = ['created','ID','state']
                      )
    #Check the df assignment:
    print ('df has been assigned', time.time()-start_time)

    #Create a .csv file from the final dataframe:
    start_time = time.time()
    df.to_csv(fr"C:\Users\ivo.vancans\OneDrive\Documents\Python Workspace\Testing Ground\{c}_sql_loop_test.csv", index = False, header=True, encoding='utf-8', sep=';')
    #Check csv file creation:
    print ('csv has been created',time.time()-start_time)

    #Close the session
    start_time = time.time()
    cursor.close()

    #Check the session closing:
    print('The cursor is closed',time.time()-start_time)

В этом примере 4 страны, потому что я пытался сократить сумму вдвое, но это тоже не помогает. Я думал, что у меня есть какие-то ограничения на запросы в конце DWH, потому что значительное замедление всегда начиналось с 5-й страны. Запуск их по отдельности занимает почти одинаковое время для каждого, но все равно занимает слишком много времени. Итак, мои тесты показывают, что l oop всегда отстает на этапе запроса данных. Каждый второй шаг занимает меньше секунды, но время запроса возрастает до 140-500, иногда даже больше, как уже упоминалось ранее. Так в чем проблема?

1 Ответ

0 голосов
/ 19 марта 2020

Нашли решение! После разговора с человеком в моей компании, у которого гораздо больше опыта работы с SQL и нашим конкретным двигателем DWH, он согласился помочь и переписать часть SQL. Вместо того, чтобы оставить присоединение к подзапросу, мне пришлось переписать его, чтобы не было подзапроса. Почему? Поскольку наш конкретный движок не создает индекс для подзапроса, ставки на отдельные объединенные таблицы будут иметь индексы. Это значительно улучшило время всего сценария: с ~ 40 минут до ~ менее 1 минуты.

...