Я пытаюсь проиндексировать свою blogentries
базу данных для повышения производительности, но обнаружил проблему.
Вот структура:
CREATE TABLE IF NOT EXISTS `blogentries` (
`id_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title_id` varchar(100) COLLATE latin1_german2_ci NOT NULL,
`entry_id` varchar(5000) COLLATE latin1_german2_ci NOT NULL,
`date_id` int(11) NOT NULL,
PRIMARY KEY (`id_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
COLLATE=latin1_german2_ci
AUTO_INCREMENT=271;
Запрос, подобный следующему, правильно использует индекс:
EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + | id | select_type | стол | тип | возможные_ключи | ключ | key_len | ref | строки | Extra | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + | 1 | ПРОСТО | Blogentries | индекс | NULL | ПЕРВИЧНЫЙ | 114 | NULL | 126 | Используя индекс | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
Тем не менее, когда я добавляю entry_id
в SELECT
запрос он использует файловую сортировку
EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + | id | select_type | стол | тип | возможные_ключи | ключ | key_len | ref | строки | Extra | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + | 1 | ПРОСТО | Blogentries | ВСЕ | NULL | NULL | NULL | NULL | 126 | Использование сортировки файлов | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
Мне было интересно, почему это происходит и как я могу избежать этого? Это из-за того VarChar
, и это должно быть изменено на что-то другое?
Я пытаюсь , чтобы все мои запросы используют индекс , как я бег в максимум Handler_read_rnd
и Handler_read_rnd_next
ценность.
Если вам нужна какая-либо другая информация, я тоже могу опубликовать ее.
WHERE 1=1
ко второму запросу.SELECT @@sort_buffer_size
)?Ответы:
Поскольку у вас нет ни одного
WHERE
предложения ни в одном запросе, вы возвращаете все строки в обоих случаях, поэтому я думаю, что использование или неиспользование индекса будет очень мало влиять на производительность в этих примерах.источник
ORDER BY
?varchar(5000)
.Как описано в разделе «
ORDER BY
Оптимизация» :В своей статье в блоге « Что такое read_rnd_buffer_size» , Петр Зайцев объясняет:
Это говорит о том, что
max_length_for_sort_data
это ограничение на общий размер столбцов, которые вы выбираете, выше которогоfilesort
будет использоваться сортировка вместо индекса.В вашем случае выбор
entry_id
(5002 байта) принимает общий размер, превышающий значение по умолчанию, равное 1 КБ, и, следовательноfilesort
, используется. Чтобы поднять лимит до 8 КБ, вы можете сделать:источник
Вы получили много интересных ответов здесь, но никто точно не ответил на вопрос - почему это происходит? Насколько я понимаю, когда запрос SELECT содержит данные переменной длины в MySQL и нет индекса, который соответствует ВСЕМ запрошенных столбцов, он всегда будет использовать файловую сортировку. Размер данных здесь не очень важен. Трудно найти прямой ответ на этот вопрос в документации по MySQL, но вот хороший пост в блоге, где кто-то испытывает проблему, очень похожую на вашу.
Смотрите также: 10 советов по оптимизации запросов MySQL (которые не отстой) .
Таким образом, если у него есть возможность иметь индекс для entry_id, вы можете добавить его и все готово. Но я сомневаюсь, что это вариант, так что делать?
Нужно ли что-то делать по этому поводу - это отдельный вопрос. Важно знать, что «файловая сортировка» в MySQL плохо названа - на самом деле это просто название алгоритма, используемого для сортировки этого конкретного запроса, и во многих случаях такая сортировка действительно происходит в памяти. Если вы не ожидаете, что эта таблица сильно вырастет, это, вероятно, не имеет большого значения.
С другой стороны, если в этой таблице будет миллион строк, у вас может быть проблема. Если вам нужно поддерживать разбиение на страницы запросов в этой таблице, то у вас может возникнуть серьезная проблема с производительностью. В этом случае разделение данных переменной длины на новую таблицу и выполнение JOIN для ее извлечения является допустимой оптимизацией, которую следует учитывать.
Вот пара других ответов на SO, которые обсуждают этот вопрос:
источник
filesort
видимому, в этом случае не использовался. Я также думаю, что даже сортировка небольшой таблицы в одной памяти может оказаться неприемлемым ударом по производительности: например, если запрос выполняется много (и таблица изменяется так, что кэши не могут использоваться).Попробуйте добавить
WHERE
предложение в ваши запросы.http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
источник
ORDER BY
делает соответствует индексу точно, поэтому нет необходимости иметьWHERE
пункт.Насколько мне известно, varchar может содержать не более 8000 байт, что составляет примерно 4000 символов. Таким образом, кажется, что 5000 превышает предел хранилища, и в этом случае, вероятно, причина, по которой сортировка испортилась.
"varchar [(n | max)] Данные переменной длины, не являющиеся символами Unicode. n может быть значением от 1 до 8 000. max указывает, что максимальный размер хранилища составляет 2 ^ 31-1 байт. Размер хранилища является фактическим длина введенных данных + 2 байта. Длина вводимых данных может быть 0 символов. Синонимы SQL-2003 для varchar различаются символами или символами. "
Надеюсь, что это ответ на ваш вопрос
источник
CHAR
VARCHAR
VARCHAR
У вас есть только 126 строк в вашей таблице. Даже если максимальный размер каждой строки составляет около 5 КБ, это означает, что общий объем для чтения с диска составляет всего около 600 КБ - это не так уж много. Честно говоря, это очень небольшое количество, вероятно, меньше, чем размер кеша большинства современных дисков.
Теперь, если серверу нужно получить ваши данные для выполнения вашего запроса, самая дорогая операция - это прочитать их с диска. Но чтение в соответствии с порядком индекса НЕ всегда является самым быстрым способом сделать это, особенно когда объем данных настолько мал.
В вашем случае гораздо эффективнее считывать данные всей таблицы с диска как отдельный блок в память (возможно, всего за одну операцию чтения с диска или выполнять поиск), а затем сортировать их в ОЗУ для удовлетворения ORDER BY, который является мгновенным по сравнению с диском операция чтения. Если сервер считывает ваши данные в соответствии с индексом, ему придется выполнить до 126 (упс!) Операций чтения, многократно просматривая один и тот же файл данных.
Другими словами, последовательное сканирование не всегда плохо, и MySQL не обязательно глупо. Если вы попытаетесь заставить mysql использовать этот индекс, он, скорее всего, будет работать медленнее, чем последовательное сканирование, которое у вас сейчас есть.
И причина, по которой он использовал индекс, когда поле размером 5 КБ не было включено, заключается в том, что извлеченные данные не составляли 99% данных в таблице. Когда вы включили свое поле размером 5 КБ, теперь запрос должен прочитать 99% данных, и дешевле будет прочитать все это и впоследствии отсортировать его в памяти.
источник
JOIN
условий иWHERE
предложений, а неORDER BY
предложений.Какую версию MySQL вы используете?
В 5.1 я попытался настроить ваш сценарий и заполнил некоторые фиктивные данные. Используя предоставленные вами SQL-запросы, я получаю только сканирование таблицы каждый раз в соответствии с EXPLAIN. По умолчанию при использовании order by MYSQL используется сортировка файлов, даже если первичный индекс используется в порядке по.
источник