Как MySQL оптимизирует LIMIT
В некоторых случаях, когда используется LIMIT # и не используется HAVING , MySQL будет выполнять запрос несколько иначе:
Если при помощи LIMIT выбираются только несколько строк, MySQL будет использовать индексы в тех некоторых случаях, когда он обычно предпочел бы делать полное сканирование таблицы.
Если LIMIT # используется с ORDER BY , MySQL закончит сортировку, как только найдет первые # строк, вместо того, чтобы сортировать всю таблицу.
При сочетании LIMIT # с DISTINCT MySQL остановится, как только найдет # уникальных строк.
В некоторых случаях группировка GROUP BY может быть выполнена путем упорядоченного считывания ключа (или путем выполнения сортировки по ключу) и последующего вычисления итогового результата пока не изменится значение ключа. В этом случае LIMIT # не будет вычислять какие-либо ненужные предложения GROUP BY .
После того как MySQL пошлет первые # строк клиенту, он прервет выполнение запроса (если не используется SQL_CALC_FOUND_ROWS ).
LIMIT 0 всегда будет быстро возвращать пустую выборку. Эта команда полезна для проверки запроса и получения типов столбцов результата.
Если сервер для выполнения запроса использует временные таблицы, LIMIT # применяется для вычисления того, сколько для них потребуется места.
Скорость выполнения запросов INSERT
Время, необходимое для вставки записи, можно грубо разделить на такие промежутки:
Подсоединение: (3)
Посылка запроса на сервер: (2)
Синтаксический анализ запроса: (2)
Вставка записи: (1 * размер записи)
Вставка индексов: (1 * число индексов)
Закрытие: (1)
где числа в скобках пропорциональны полному времени. При этом не учитывается время в начале вставки, требующееся для открытия таблиц (таблицы открываются один раз для каждого конкурентно выполняющегося запроса).
Размер таблицы замедляет вставку индексов в log N раз (B-деревья).
Некоторые способы ускорения вставки:
Если с одного клиента одновременно вставляется большое количество строк, используйте операторы INSERT в форме, содержащей множество записей. При этом вставка будет происходить намного быстрее (в некоторых случаях в несколько раз), чем при использовании отдельных операторов INSERT . При добавлении данных в непустую таблицу можно настроить переменную myisam_bulk_insert_tree_size так, чтобы это делалось еще быстрее. См. раздел SHOW VARIABLES .
При вставке нескольких строк с различных клиентов можно повысить скорость, используя оператор INSERT DELAYED . См. раздел Синтаксис оператора INSERT .
Обратите внимание: при использовании таблиц MyISAM можно вставлять строки во время выполнения операторов SELECT , если в таблицах нет удаленных строк.
При загрузке таблицы из текстового файла используйте команду LOAD DATA INFILE . При этом обычно вставка будет происходить в 20 раз быстрее, чем при использовании соответствующего количества операторов INSERT . См. раздел Синтаксис оператора LOAD DATA INFILE .
Если таблица имеет много индексов, можно проделать некоторую дополнительную работу, чтобы команда LOAD DATA INFILE выполнялась еще быстрее. Используйте следующую процедуру:
При необходимости создайте таблицу при помощи оператора CREATE TABLE (например, используя mysql или Perl-DBI ).
Выполните оператор FLUSH TABLES или команду оболочки: mysqladmin flush-tables .
Используйте myisamchk --keys-used=0 -rq /path/to/db/tbl_name . После этого индексы не будут использоваться для данной таблицы.
Вставьте данные в таблицу при помощи LOAD DATA INFILE . При этом никакие индексы обновляться не будут и, следовательно, скорость будет высокой весьма.
Если вы собираетесь в будущем только лишь читать таблицу, выполните myisampack для этой таблицы, чтобы уменьшить ее размер. См. раздел myisampack , MySQL-генератор сжатых таблиц (только для чтения).
Воссоздайте индексы при помощи команды myisamchk -r -q /path/to/db/tbl_name . Эта процедура создает индексное дерево в памяти, перед тем как записать его на диск, что гораздо быстрее за счет исключения большого количества дисковых операций. Индексное дерево, получившееся в результате, к тому же отлично сбалансировано.
Выполните оператор FLUSH TABLES или команду оболочки: mysqladmin flush-tables .
Обратите внимание: команда LOAD DATA INFILE также выполняет вышеупомянутую оптимизацию при вставках в пустую таблицу. Главное отличие этой команды от вышеупомянутой процедуры заключается в том, что при помощи myisamchk можно выделить намного больше временной памяти для создания индекса, чем MySQL, по вашему мнению, должен выделять для каждого воссоздания индексов. Начиная с MySQL 4.0 можно также использовать команду ALTER TABLE tbl_name DISABLE KEYS вместо myisamchk --keys-used=0 -rq /path/to/db/tbl_name и ALTER TABLE tbl_name ENABLE KEYS вместо myisamchk -r -q /path/to/db/tbl_name . Таким образом можно также пропускать шаги FLUSH TABLES .
Можно ускорять операции вставки, выполняемые несколькими операторами, путем установки блокировки таблиц:
mysql> LOCK TABLES a WRITE; mysql> INSERT INTO a VALUES (1,23),(2,34),(4,33); mysql> INSERT INTO a VALUES (8,26),(6,29); mysql> UNLOCK TABLES;
Главный фактор, влияющий на скорость, - то, что буфер индексов сбрасывается на диск только один раз, после завершения всех операторов INSERT . Обычно содержимое индексных буферов сбрасывалось бы на диск столько раз, сколько имеется различных операторов INSERT . Блокировка не нужна, если можно вставить все строки при помощи одного оператора. Для транзакционных таблиц, чтобы повысить скорость, следует использовать BEGIN/COMMIT вместо LOCK TABLES . Блокировка также понизит полное время проверки подсоединений (multi-connection tests), но максимальное время ожидания для некоторых потоков повысится (потому что они ожидают снятия блокировки). Например:
поток 1 делает 1000 вставок потоки 2, 3 и 4 делают 1 вставку поток 5 делает 1000 вставок
Если блокировка не используется, 2, 3, и 4 завершат выполнение раньше, чем 1 и 5. Если блокировка используется, 2, 3 и 4, видимо, не закончат выполнение раньше, чем 1 или 5, но общее время должно приблизительно уменьшиться на 40%. Так как в MySQL операции INSERT , UPDATE и DELETE очень быстрые, общая производительность будет улучшаться, если добавлять блокировки ко всем командам, делающим более 5 вставок или обновлений подряд. Если делается очень много вставок строк, можно время от времени сопровождать команду LOCK TABLES командой UNLOCK TABLES (после каждых 1000 строк), чтобы позволить другим потокам обращаться к таблице. Результатом всего этого будет получение хорошей производительности. Конечно, для загрузки данных намного более быстрой является команда LOAD DATA INFILE .
Чтобы дополнительно повысить скорость выполнения команд LOAD DATA INFILE и
INSERT , увеличьте буфер ключа (key buffer ). См. раздел Настройка параметров сервера.
1 2 3 4 5 6 7
8 8 8
| |