2016-06-17 3 views
0

Мы используем Python и LOAD DATA INFILE для загрузки данных из CSV в нашу промежуточную базу данных. Начиная с этапа, у нас есть sql-скрипты, перемещающие данные в нашу фактическую производственную базу данных.MySQL insert with sub select slow

LOAD DATA INFILE молниеносно по сравнению с выбором рядов от постановки и вводом их в производство.

Мы на 5,7, используя InnoDB и мы применили следующую конфигурацию, чтобы оптимизировать наши вставки:

  • Набор innodb_autoinc_lock_mode до 2
  • Установить размер InnoDB пул буферов на половину памяти (16 Гб)
  • Установите размер буфера для журнала до 4 ГБ
  • Мы используем ОПЕРАЦИИ
  • Использовать SET autocommit = 0;

Все еще вставка из одной таблицы в другую значительно медленнее по сравнению с LOAD DATA INFILE.

Когда я смотрю на записи ввода-вывода, с данными загрузки данных он достигает до 30 МБ/с, тогда как с обычными вставками максимальный 500 КБ/с.

Есть ли способ улучшить эту производительность или нам нужно полностью пересмотреть наш подход. Я могу думать об использовании OUTFILE для вспомогательных запросов и загружать их обратно с помощью INFILE, но это не похоже на правильный подход.

И заявление:

INSERT INTO documentkey (documentClassCode,dId,fileTypeCode,internet,pathId,creationTime,signature,CSVimportId) 
SELECT case when csv.`Document Class` is null 
       then (select classCode from mydb.class where classDesc = 'Empty' 
        And LookupId = (select LookupId from mydb.Lookup where LookupGroupCode = 'C' and EntityLookedup = 'documentkey') 
        ) 
       else (select classCode from mydb.class where classDesc = csv.`Document Class` 
        And LookupId = (select LookupId from mydb.Lookup where LookupGroupCode = 'C' and EntityLookedup = 'documentkey') 
        ) 
     end, 
     csv.`dId`, 
     (select typeCode from mydb.type 
       Where typeDesc = csv.`File Type` 
       And LookupId = (select LookupId from mydb.Lookup where LookupGroupCode = 'T' and EntityLookedup = 'documentkey') 
     ), 
     case when csv.`message ID` is null 
       then (select messageIncrId from message where internetdesc = 'Empty') 
       else case when exists (select internetMessageIncrId from internetMessage where internetdesc = csv.`Internet Message ID`) 
          then (select internetMessageIncrId from internetMessage where internetdesc = csv.`Internet Message ID`) 
          else 0 
        end 
     end, 
     case when exists (select pathId from Path where pathDesc = csv.`path`) 
       then (select pathId from Path where pathDesc = csv.`path`) 
       else 0 
     end, 
     case when csv.`Creation Time` <> '' then STR_TO_DATE(csv.`Creation Time`, '%d/%m/%Y %H:%i:%s') else '2016-06-16 10:00:00' end, 
     #STR_TO_DATE(csv.`Creation Time`, '%Y-%m-%d %H:%i:%s'), 
     csv.`Signature Hash`, 
     1 
     #csv.`CSV import id` 
FROM `mydb_stage`.`csvDocumentKey` csv 
where csv.`dId` is not null and csv.threadId = @thread; 

Выберите часть запроса занимает лишь доли секунды.

Объясните:

'1', 'PRIMARY', 'csv', NULL, 'ALL', NULL, NULL, NULL, NULL, '1', '100.00', 'Using where' 
'12', 'DEPENDENT SUBQUERY', 'path', NULL, 'eq_ref', 'pathDesc_UNIQUE', 'pathDesc_UNIQUE', '1026', 'func', '1', '100.00', 'Using where; Using index' 
'11', 'DEPENDENT SUBQUERY', 'path', NULL, 'eq_ref', 'pathDesc_UNIQUE', 'pathDesc_UNIQUE', '1026', 'func', '1', '100.00', 'Using where; Using index' 
'10', 'SUBQUERY', 'message', NULL, 'const', 'messageDesc_UNIQUE', 'messageDesc_UNIQUE', '2050', 'const', '1', '100.00', 'Using index' 
'9', 'DEPENDENT SUBQUERY', 'message', NULL, 'eq_ref', 'messageDesc_UNIQUE', 'messageDesc_UNIQUE', '2050', 'func', '1', '100.00', 'Using where; Using index' 
'8', 'DEPENDENT SUBQUERY', 'message', NULL, 'eq_ref', 'messageDesc_UNIQUE', 'messageDesc_UNIQUE', '2050', 'func', '1', '100.00', 'Using where; Using index' 
'6', 'DEPENDENT SUBQUERY', 'type', NULL, 'eq_ref', 'typeDesc_UNIQUE', 'typeDesc_UNIQUE', '1026', 'func', '1', '100.00', 'Using index condition; Using where' 
'7', 'SUBQUERY', 'Lookup', NULL, 'ref', 'PRIMARY', 'PRIMARY', '6', 'const', '3', '10.00', 'Using where' 
'4', 'SUBQUERY', 'class', NULL, 'const', 'classDesc_UNIQUE', 'classDesc_UNIQUE', '1026', 'const', '1', '100.00', NULL 
'5', 'SUBQUERY', 'Lookup', NULL, 'ref', 'PRIMARY', 'PRIMARY', '6', 'const', '2', '10.00', 'Using where' 
'2', 'DEPENDENT SUBQUERY', 'class', NULL, 'eq_ref', 'classDesc_UNIQUE', 'classDesc_UNIQUE', '1026', 'func', '1', '20.00', 'Using index condition; Using where' 
'3', 'SUBQUERY', 'Lookup', NULL, 'ref', 'PRIMARY', 'PRIMARY', '6', 'const', '2', '10.00', 'Using where' 
+0

Одна из причин 'LOAD DATA' - это быстро, потому что на самом деле это не делает какой-либо материал базы данных, тогда как' INSERT'. –

+0

@TimBiegeleisen Я предполагаю, что он работает с определенными настройками конфигурации, которые являются прозрачными для пользователя, и я бы предположил, что вы могли бы достичь аналогичной конфигурации и, следовательно, производительности для INSERT. Это просто вопрос о том, как. – L4zl0w

+0

Как вы выбираете и вставляете данные. вы можете показать нам запрос –

ответ

1

Вы не упоминаете, почему вы хотите изменить свой подход, особенно если производительность вас основная цель.
ВЫБРАТЬ может не быть так быстро, как демпинг файла в виде таблицы и уже указан в явном виде в документации MySQL
От insert-speed

При загрузке таблицы из текстового файла, используйте НАГРУЗКИ INFILE DATA , Это обычно в 20 раз быстрее, чем при использовании инструкций INSERT. См. Раздел . 14.2.6, «Синтаксис данных загрузки данных».

+0

спасибо, нам нужно загрузить в 1 миллиард записей менее чем за 12 часов до постановки и оттуда в производство. Теперь получение записей в постановку не является проблемой, но от постановки к постановке занимает очень много времени. Я не понимаю, почему INSERT с выбором медленный, если оператор SELECT работает быстро. Я бы предположил, что результат выражения select находится в памяти, откуда он должен быть быстро вставлен. Но я явно что-то пропустил, потому что это не то, что я испытываю. – L4zl0w

+0

'INSERT' медленный, потому что MySQL является совместимым с ACID и использует 1 ввод-вывод вашего диска для выполнения вставки. Группировка вставок в транзакции позволяет использовать диск 1 ввода/вывода, но использует гораздо большую пропускную способность. LOAD DATA INFILE избегает уровня SQL и эффективно использует диск. Причина, по которой вы испытываете медлительность, связана с вашим жестким диском. Получите проданные государственные диски для вашего сервера (-ов) сервера и обратите внимание на их количество IOPS. Вы ничего не решите, написав оптимальный код - это также связано с оборудованием, вы можете идти только до сих пор с помощью кода. –

+0

Я понимаю, но это утверждение значительно медленнее, чем другие, более простые инструкции вставки. Я говорю ~ 20 раз медленнее. С этим утверждением записывается только 150-400 КБ. Это не «узкое место» ввода-вывода. – L4zl0w