2013-06-28 4 views
0

Я проделал много поиска/чтения по этой теме, но я все еще не в состоянии решить проблему.Скорость MySQL SELECT (индексы стоят на столбцах с небольшим изменением)?

У меня есть таблицы с десятками или сотнями тысяч строк, общаясь где-то в области 300 ГБ данных. Столбец, который мне нужно выбрать, содержит много HTML, которые могут быть частью проблемы. Я использую COMPRESS. Запрос содержит два предложения WHERE:

SELECT id, olr_id, COMPRESS(source_html) 
FROM buildings 
WHERE scrape_status=1 
AND parse_status=0 LIMIT 1; 

Как и следовало ожидать, id является первичным ключом. Кроме того, olr_id - уникальный индекс. Этот запрос занимает примерно 160-300 секунд, чтобы вернуть результат, что совершенно невозможно. Странно (по крайней мере для меня), удаление предложения WHERE для parse_status приводит к завершению запроса менее чем за 2-3 секунды. Сначала я подумал, что, возможно, это было связано с тем, что это было слишком специфично, поэтому я даже попытался удалить scrape_status и только запустил предложение WHERE, но, видимо, это конкретное предложение, вызывающее безумное увеличение времени выполнения.

Дело в том, что я не знаю, будет ли индексирование этих столбцов даже хорошим (scrape_status и parse_status), поскольку их диапазон значений 0-2. Думаю, это мой главный вопрос - поможет ли он индексировать столбец с такой небольшой дисперсией в значениях? Я где-то читал где-то, что индексирование действительно лучше подходит для столбцов с большими вариациями, но, как я уже сказал, я не согласен с идеями, а 160-300 секунд просто совершенно необоснован для сотен тысяч записей.

Любой вход будет оценен очень. Если вам понадобится дополнительный вход, чтобы помочь мне, я был бы рад предоставить. На этой ноте, они являются EXPLAIN результатов для каждого из трех запросов:

id: 1 
select_type: SIMPLE 
table: building 
type: ALL 
possible_keys: null 
key: null 
key_len: null 
ref: null 
rows: 58664 
Extra: Using where 

Я ценю ваше время в чтении и предлагая любую помощь, что вы можете.

+0

Просто идея, я даже не уверен, как вы это сделаете, но я думаю, что вы можете пометить половину своей таблицы, а затем запустить два запроса одновременно (разветвление или что-то в этом роде) одним движением через первую половину, и один проходит через вторую половину стола. – throwaway2013

+0

Если вы добавили составной индекс для анализа и очистки, запрос будет быстрым. Индекс, как вы говорите, будет болезненным. Почему вы получаете нужное значение, как в первом случае, когда СУБД сталкивается (Limit 1)? –

+0

@CppandQtBeginner Я рассмотрю это как возможное решение. –

ответ

2

Создание составного индекса обоих столбцов в предложении WHERE:

CREATE INDEX ix_sp ON buildings (scrape_status, parse_status); 

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

Попробуйте следующее, а также:

SELECT b1.id, olr_id, COMPRESS(source_html) 
from buildings b1 
JOIN (SELECT id 
     FROM buildings 
     WHERE scrape_status=1 
     AND parse_status=0 
     LIMIT 1) b2 
USING (id) 

Ваш исходный запрос может сжимать все совпадающие строки, даже если большинство из них выбрасываются в пункте LIMIT. Эта версия только сжимает одну выбранную строку.

+0

Нет, MySQL не оценивает выражения в списке выбора для строк, пока не определит, что они соответствуют условиям в предложении WHERE. Вы можете проверить это: 'SELECT SLEEP (1) FROM SomeTable WHERE unindexed_column = 123' и посмотреть, будет ли оно спящим столько секунд, сколько количества строк в таблице, или как число строк, которые имеют значение 123. –

+0

@BillKarwin проблема не является предложением WHERE, это предложение LIMIT. – Barmar

+0

@Barmar Спасибо за отличный ответ. Вы также приводите меня к второй (может быть, немного легче) идее. Я заметил, что если я запускаю запрос без выбора 'source_html', это намного быстрее. Я могу выбрать без, найти идентификатор первой соответствующей строки, а затем выбрать source_html этой строки. Я собираюсь сделать это и посмотреть, что произойдет, прежде чем обращаться со всеми обновлениями индекса. –

0

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

В таком случае решение о создании индекса основывается на том, какой процент строк соответствует вашим условиям scrape_status=1 и parse_status=0. Например, предположим, что scrape_status=1 соответствует 2% строк, а parse_status=0 соответствует 1% строк, я бы хотел использовать parse_status в качестве ведущего столбца индекса.

Если это так, но почти все строки с parse_status=0 также имеют scrape_status=1, тогда может быть немного дополнительного преимущества для создания составного индекса.Если scrape_status=1 эффективен при дальнейшем ограничении совпадающих строк, то вы определенно хотите, чтобы он был встроен в индекс.

У MySQL также есть оптимизация для LIMIT. см. http://dev.mysql.com/doc/refman/5.6/en/limit-optimization.html Он пытается освободиться от запроса, как только найдет нужное количество совпадающих строк. MySQL 5.6 добавил некоторые новые оптимизации в этой области.

MYSQL не вычисляет выражения select-list для строк, которые не соответствуют условиям в предложении WHERE.

Однако MySQL делает должен считывать строки данных с диска, чтобы оценить их в соответствии с условиями в предложении WHERE. Этот ввод-вывод является источником большой стоимости исполнения, и это является причиной того, что сужение поиска с помощью индексов так важно. И если ваш столбец source_html является столбцом TEXT, содержащим длинные строки, вполне вероятно, что это добавит дополнительные накладные расходы для ввода-вывода, потому что MySQL будет читать дополнительные страницы данных с диска (более подробную информацию см. В разделе Blob Storage in Innodb).

Смежные вопросы