Очень медленный запрос соединения на большой таблице (машина = Xeon 2,4 ГГц, 16 ядер, 64 ГБ ОЗУ) - PullRequest
1 голос
/ 18 августа 2011

Вот мой запрос:

SELECT  email_data.id, email_data.source_file, email_data.report_id,
        email_data.filePath, email_data.fileName, email_data.size,
        email_data.emailID, email_data.msgID, email_data.cus, email_data.subject,
        email_data.sentto, email_data.emailFrom, email_data.hdrs, email_data.cc,
        email_data.bcc, email_data.extracted, email_data.DateTime,
        email_data.TimeStamp, email_data.OriginalDateTime, email_data.ParentID,
        email_data.reply_to, email_data.MD5Hash, email_data.duplicated,
        email_data.TimeZone, email_data.AttachName, email_data.fqdn, 
        attach_data.id, attach_data.source_file, attach_data.report_id,
        attach_data.filePath, attach_data.fileName, attach_data.size, attach_data.ext,
        attach_data.emailID, attach_data.cus, attach_data.extracted,
        attach_data.MD5Hash, attach_data.duplicated
FROM email_data 
LEFT JOIN attach_data
ON (email_data.emailID = attach_data.emailID);

Комбинация обеих таблиц имеет 50k + записей (email_data имеет 22k записей, а другие имеют 30K + записей).

Выше запрос берет верх90 минут и все еще не закончено.

Этот:

SELECT email_data.id, attach_data.id 
FROM email_data 
LEFT JOIN attach_data 
ON (email_data.emailID = attach_data.emailID);

занимает 2 минуты 22 секунды:

Что я делаю не так?Похоже, что MySQL не использует достаточно памяти для ускорения, и он использует только 1 ядро ​​из 16 ядер.

Как я могу настроить его для использования всех доступных ресурсов?

Или долженЯ запрашиваю идентификаторы (как во втором запросе) и зацикливаюсь + выбираю каждый из них обратно в моем коде?Приведет ли это к тому же результату?

Мне нужны все эти поля и все строки, я преобразовываю их в пользовательский формат, похожий на CSV, чтобы его можно было экспортировать в другое программное обеспечение.1021 *

mysql> show columns from email_data;
+------------------+----------+------+-----+---------+----------------+
| Field            | Type     | Null | Key | Default | Extra          |
+------------------+----------+------+-----+---------+----------------+
| id               | int(11)  | NO   | PRI | NULL    | auto_increment |
| source_file      | longtext | YES  |     | NULL    |                |
| report_id        | int(11)  | YES  |     | NULL    |                |
| filePath         | longtext | YES  |     | NULL    |                |
| fileName         | longtext | YES  |     | NULL    |                |
| size             | int(11)  | YES  |     | NULL    |                |
| emailID          | longtext | YES  |     | NULL    |                |
| msgID            | longtext | YES  |     | NULL    |                |
| cus              | longtext | YES  |     | NULL    |                |
| subject          | longtext | YES  |     | NULL    |                |
| sentto           | longtext | YES  |     | NULL    |                |
| emailFrom        | longtext | YES  |     | NULL    |                |
| hdrs             | longtext | YES  |     | NULL    |                |
| cc               | longtext | YES  |     | NULL    |                |
| bcc              | longtext | YES  |     | NULL    |                |
| extracted        | longtext | YES  |     | NULL    |                |
| DateTime         | char(1)  | YES  |     | NULL    |                |
| TimeStamp        | int(11)  | YES  |     | NULL    |                |
| OriginalDateTime | char(1)  | YES  |     | NULL    |                |
| ParentID         | longtext | YES  |     | NULL    |                |
| reply_to         | longtext | YES  |     | NULL    |                |
| MD5Hash          | longtext | YES  |     | NULL    |                |
| duplicated       | char(1)  | YES  |     | NULL    |                |
| TimeZone         | char(1)  | YES  |     | NULL    |                |
| AttachName       | longtext | YES  |     | NULL    |                |
| fqdn             | longtext | YES  |     | NULL    |                |
+------------------+----------+------+-----+---------+----------------+

Почти то же самое для attach_data

Ответы [ 5 ]

3 голосов
/ 18 августа 2011

Почти наверняка у attach_data.emailID отсутствует индекс. Учтите, что механизм запросов должен пройти каждую строку данных электронной почты, а если индекс отсутствует, он должен пройти каждую строку attach_data, даже после нахождения соответствия.

Вы должны выполнить EXPLAIN в своем запросе, чтобы увидеть, что на самом деле делает MySql. Если индекс отсутствует, вы будете выполнять 22 000 x 30 000 сравнений или около 660 миллионов сравнений для построения результирующего набора данных. Если ваши идентификаторы - строки, вас ждет долгая поездка.

Если вы сделаете индекс attach_data.emailId, вы уменьшите количество сравнений примерно до 22 000 x log (30 000), или примерно до 330 тысяч сравнений. Огромная разница. Использование индекса HASH сделает это еще быстрее (нижняя граница - 22 000 сравнений). Если индексы отсутствуют, вы можете прикрепить их по факту.

И, честно говоря, вы должны рассмотреть LIMIT, чтобы пропустить и взять окно результатов. Это избавит вас от скорби, перетасовывая эти данные клиенту. Возможно, вы обнаружите, что такой трафик может вызывать тайм-ауты при медленном соединении (и я согласен с другим постером, странно, что вы не выбрасываете время)

UPDATE

Святая корова. Увидев ваше обновление вопроса, вы должны обязательно отозвать только нетекстовые поля, выполнить итерацию по ним и вытащить полнотекстовые поля по одному за раз. Но так как вам нужно выгрузить таблицу mysql в csv, я бы порекомендовал посмотреть mysqldump . Он может создать резервную копию вашей базы данных до файлов CSV.

1 голос
/ 18 августа 2011

Во-первых, один запрос никогда не будет использовать несколько ядер (AFAIK mysql и большинство других СУБД).

Ваш второй запрос показывает, что mysql может использовать индекс (или использовать большой кэш), это хорошо.

Если ваш диск медленный и длинные тексты содержат много данных, просто потянитеЭто может привести к замедлению работы с памятью и поглотить ваши страницы индекса памяти.

Если это серьезное приложение, я бы переключился на PostgreSQL или другую БД в качестве долгосрочного решения.По моему опыту, mysql быстр только для тривиальных задач.

1 голос
/ 18 августа 2011

Я думаю, что вы путаете оптимизатор. Попробуйте добавить индекс для attach_data.emailID. Вы можете использовать оператор EXPLAIN , чтобы выяснить, что происходит.

1 голос
/ 18 августа 2011

Не уверен, что вы сделали, чтобы запрос выполнялся 90 минут, а не timeout ...

Проверьте поле, к которому вы присоединяетесь.В частности, посмотрите на план выполнения для запроса (или примерный план выполнения), чтобы увидеть, какая операция наиболее затратна.

Присоединяетесь ли вы к полям, которые являются varchar (255).varchar (max) или аналогичный?Сравнение больших varchars - дорогостоящая операция.Если вы можете сократить поле, которое могло бы помочь.

Относительно всех этих полей:

Возвращает меньшее подмножество полей.Если вы вызываете фактические данные вложения с сервера sql, то вы можете сначала выполнить запрос, чтобы определить, какие именно вложения (attach_data.PrimaryKey) необходимы, а не всю строку (которая затем должна быть извлечена в память).Затем, когда у вас есть PK с необходимыми записями attach_data, вы можете вызывать только те данные, которые необходимы для этих строк

Присоединяетесь ли вы к неиндексированным полям (как в случае с , а не присоединение по первичному ключу)?Добавление индексов к столбцам ускорит процесс извлечения, но прежде чем делать это, изучите индексы (например, добавление индексов к столбцу на самом деле замедляет обновление / вставку данных, а индексы в полях int лучше, чем индексы в широком диапазоне varchars).

0 голосов
/ 18 августа 2011

Вы действительно хотите, чтобы все строки были удалены из таблицы? Было бы намного лучше, если бы вы могли выполнять меньшие запросы на то, что вам нужно в определенный момент процесса. В идеале вы должны добавить куда-то предложение where. Истинное отставание, вероятно, связано с чтением его с жесткого диска. Выполнение настроек RAID с рекурсивным резервным копированием может как-то ускорить это, но я не уверен.

Вы можете изменить некоторые настройки MySQL и указать максимальный объем памяти, который будет использоваться для запроса, а также некоторые другие параметры.

http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...