MySQL "Отправка данных" ужасно медленно
У меня есть таблица скромного размера, 277 тыс. записей на данный момент, которую я пытаюсь выполнить FULLTEXT
. Поиск кажется очень быстрым, пока он не дойдет до фазы отправки данных.
Таблица:
CREATE TABLE `sqinquiries_inquiry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ts` datetime NOT NULL,
`names` longtext NOT NULL,
`emails` longtext NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `sqinquiries_inquiry_search` (`names`,`emails`)
) ENGINE=MyISAM AUTO_INCREMENT=305560 DEFAULT CHARSET=latin1
Запрос:
SELECT * FROM `sqinquiries_inquiry` WHERE (
MATCH (`sqinquiries_inquiry`.`names`) AGAINST ('smith' IN BOOLEAN MODE) OR
MATCH (`sqinquiries_inquiry`.`emails`) AGAINST ('smith' IN BOOLEAN MODE)
) ORDER BY `sqinquiries_inquiry`.`id` DESC LIMIT 100
Профиль: (я вырезал, казалось бы, бесполезную информацию)
+-------------------------+----------+
| Status | Duration |
+-------------------------+----------+
| preparing | 0.000014 |
| FULLTEXT initialization | 0.000015 |
| executing | 0.000004 |
| Sorting result | 0.000008 |
| Sending data | 2.247934 |
| end | 0.000011 |
| query end | 0.000003 |
+-------------------------+----------+
DESCRIBE
выглядит великолепно, просто один лайнер:
Опишите:
id: 1
select_type: SIMPLE
table: sqinquiries_inquiry
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 100
Extra: Using where
Так что я не понимаю, откуда взялось 2.25 секунд данных отправки? Я вижу подобную производительность в Python и в консольном приложении mysql
, оба подключаются к localhost
.
Обновление:
- За комментарий, запрашивающий средний размер строки, это: 53.8485
- За комментарий здесь находится
DESCRIBE
.
Ответы
Ответ 1
DESCRIBE
выглядит великолепно, простой один вкладыш.
Поскольку в вашем запросе используется только одна таблица, это не может быть ничего, кроме однострочного.
Однако ваш запрос не использует индекс FULLTEXT
.
Чтобы индекс мог использоваться, вы должны немного переписать запрос:
SELECT *
FROM sqinquiries_inquiry
WHERE MATCH (names, emails) AGAINST ('smith' IN BOOLEAN MODE)
ORDER BY
id DESC
LIMIT 100
MATCH
использует только индекс, если вы сопоставляетесь с точным набором столбцов, на котором указан индекс.
Таким образом, ваш запрос использует сканирование индекса на id
: Using index; Using where
в самом конце вашего DESCRIBE
.
Sending data
довольно вводит в заблуждение: это фактически время, прошедшее между окончанием предыдущей операции и окончанием текущей операции.
Например, я просто выполнил этот запрос:
SET profiling = 1;
SELECT *
FROM t_source
WHERE id + 1 = 999999;
SHOW PROFILE FOR QUERY 39;
который возвратил одну строку и этот профиль:
'starting', 0.000106
'Opening tables', 0.000017
'System lock', 0.000005
'Table lock', 0.000014
'init', 0.000033
'optimizing', 0.000009
'statistics', 0.000013
'preparing', 0.000010
'executing', 0.000003
'Sending data', 0.126565
'end', 0.000007
'query end', 0.000004
'freeing items', 0.000053
'logging slow query', 0.000002
'cleaning up', 0.000005
Поскольку индекс не используется, MySQL
необходимо выполнить полное сканирование таблицы.
0.126565
секунды - это время с начала выполнения (время чтения первой строки) и конец выполнения (время последней строки было отправлено клиенту).
Эта последняя строка находится в самом конце таблицы, и она долгое время находила и отправляла ее.
P. S.
Отредактировано, чтобы удалить нижний план:)
Ответ 2
Я думаю, вы переносите много данных медленным сетевым подключением.
Вместо select * сделайте только те столбцы, которые вам действительно нужны.
Если ваша таблица содержит большие текстовые поля, которые вы хотите показать в результате, вы можете использовать подстроку, чтобы передавать только первые несколько символов/слов текста.
Некоторые клиенты поддерживают сжатие пакетов результатов. Возможно, вам нужно взглянуть на это.