2016-06-20 1 views
1

Вопрос

Я пытаюсь прочитать таблицу на MS SQL Server с использованием python, в частности SQLalchemy, pymssql и pandas.read_sql. Я хочу выполнить запрос, поместить результаты в pandas Dataframe и продолжить свой день с разумной скоростью, но довольно простой запрос (output = 100 MB) занимает почти 5-10 минут на LAN-подключении, используя ethernet кабели - нет Wi-Fi в поле зрения.SQLalchemy - pymssql - pandas всегда медленный, или я делаю это неправильно?

Результирующий информационный кадр с 3 колонками и 3214086 элементами занял колоссальные 423 секунды. Следующая информация():

Int64Index: 3214086 entries, 0 to 3214085 
Data columns (total 3 columns): 
DateTime datetime64[ns] 
TagName  object 
Value  float64 
dtypes: datetime64[ns](1), float64(1), object(1) 
memory usage: 98.1+ MB 
None 

Если моя математика является правильным, 100 МБ в 423 секунд составляет около 230 Кб/с, что я думаю, через соединение Ethernet просто мучительно медленно. Узким должно быть на сервере SQL сам


Запрос информации

SQL сервер сам по себе является Wonderware настройки, которые могут или не могут иметь что-то делать с этим. В следующем запросе я запрашиваю значения 6 разных тегов за период 1 месяц, где разрешение составляет 5000 мс или 5 секунд.

Вот что сам запрос выглядит следующим образом:

sql_query = ''' 
SELECT DateTime, TagName, Value 

    FROM Runtime.dbo.AnalogHistory 

    WHERE 
     DateTime BETWEEN '2014-05-26 00:00' AND '2014-06-26 00:00' 
    AND 
     TagName IN (
      'Tag1.ActualValue', 
      'Tag2.ActualValue', 
      'Tag3.ActualValue', 
      'Tag4.ActualValue', 
      'Tag5.ActualValue', 
      'Tag6.ActualValue') 
    AND 
     wwRetrievalMode = 'Cyclic' 
    AND 
     wwResolution = 5000 
''' 

И, наконец, функция ExecuteQuery:

import pandas as pd 
import pymssql 
import sqlalchemy 

def executeQuery(sql_query): 
    connection_string = 'mssql+pymssql://user:[email protected]' 
    engine = sqlalchemy.create_engine(connection_string) 

    df = pd.read_sql(sql_query, engine) 

    if 'DateTime' in df.columns: 
     df.DateTime = pd.to_datetime(df.DateTime, infer_datetime_format=True) 

    return df 

Вопрос

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

This question похоже, связано с тем, что ОП пытался написать серверу sql. Там говорится, что быстрее использовать «BULK INSERT» вместо pandas, используя CSV-файл, но это не является жизнеспособным вариантом для чтения с SQL-сервера. Должен ли я иметь каталог, содержащий CSV-файлы всей даты/времени и всех тегов !? Это в первую очередь отрицает использование сервера sql, не так ли?

+0

Можете ли вы также указать, какие индексы определены для таблицы «Runtime.dbo.AnalogHistory» и план выполнения этого запроса? – MaxU

+0

Я не знаю, как это сделать, это вариант, который я предоставляю запросу или определяю через MS Management Studio? – cbcoutinho

+1

Пожалуйста, проверьте SO или попросите Google, как найти индексы и план выполнения. Кроме того, вы хотели бы знать, сколько строк в общей таблице есть в этой таблице и насколько оно велико ... Вы извлекаете целые 3,2 М строк всего за один месяц, один «wwResolution» и 6 тегов, поэтому ваша таблица может содержат намного больше, и если ваш оператор select будет выполнять FTS (Full Table Scan), это означает, что MS SQL сначала будет сначала читать всю таблицу, применять фильтры и возвращать данные клиенту. Это можно увидеть в плане выполнения запроса. – MaxU

ответ

2

Я думаю, вы звоните в свою executeQuery() функцию в цикле - довольно много раз и каждый раз, когда вы воссоздаете механизм SQLAlchemy, что делает его медленным.

Так попытайтесь создать соединение с базой данных один раз и использовать его несколько раз:

import pandas as pd 
import pymssql 
import sqlalchemy 

connection_string = 'mssql+pymssql://user:[email protected]' 
engine = sqlalchemy.create_engine(connection_string) 

def executeQuery(sql_query, engine=engine): 
    df = pd.read_sql(sql_query, engine) 

    # i'm not sure that you really need it ... 
    if 'DateTime' in df.columns: 
     df.DateTime = pd.to_datetime(df.DateTime, infer_datetime_format=True) 

    return df 

PS если ваш DateTime колонке на стороне MS SQL имеет тип данных DateTime, SQLAlchemy следует сопоставить его с Python datetime типа. Таким образом, в конце концов, это должно быть уже np.datetime64 ...

Если вы звоните это один раз или очень несколько раз, то я хотел бы сделать следующее:

  • Проверьте план выполнения (используются индексы, асимметрию данных , и т.д.)
  • выполнить этот запрос на сервер MS SQL - и измерить время выполнения
  • выполнить этот запрос на клиентском компьютере по сети - и измерить время выполнения

После того, что вы будете видеть, где вы 're теряете время больше ...

+0

Принимая утверждение связи из функции, имеет смысл; однако, похоже, это не улучшает ситуацию на моей стороне. Во-вторых, мне еще не удалось использовать параметр parse_dates – cbcoutinho