Недавно я начал писать SQL-запрос для анализа и отладки рабочего кода. Но я был удивлен, увидев, что выполнение некоторых запросов занимает больше времени для достижения того же результата. Я провел исследование и обнаружил некоторые интересные вещи о том, как отлаживать SQL-запрос. У меня есть очень простая таблица, определение которой заключается в следующем. В тестовой среде эта таблица была заполнена более чем 1000 тысячами строк.
01
02
03
04
05
06
07
08
09
10
|
+-----------------------+--------------+------+-----+----------------+ | Field | Type | Null | Key | Extra | +-----------------------+--------------+------+-----+----------------+ | id | bigint( 20 ) | NO | PRI | auto_increment | | dateCreated | datetime | NO | | | | dateModified | datetime | NO | | | | phoneNumber | varchar( 255 ) | YES | MUL | | | version | bigint( 20 ) | NO | | | | oldPhoneNumber | varchar( 255 ) | YES | | | +-----------------------+--------------+------+-----+----------------+ |
Я выполнил очень простой запрос, чтобы найти кортеж, содержащий 5107357058 в качестве номера телефона. Потребовалось почти 4 секунды, чтобы получить результат.
1
2
|
select * from Device where phoneNumber = 5107357058 ; takes 4 sec. |
Этот простой запрос должен был занять несколько миллисекунд. Я заметил, что тип данных phoneNumber varchar, но в запросе он указан как число. Когда я модифицирую запрос, чтобы он соответствовал типу данных, это заняло несколько миллисекунд.
1
2
|
select * from Device where phoneNumber = '5107357058' ; takes almost no time. |
После поиска в Google и чтения поста в stackoverflow я обнаружил EXPLAIN
SQL clouse, который помогает в отладке запроса. Оператор EXPLAIN
предоставляет информацию о плане выполнения для SELECT
. Когда я использовал его для получения информации о двух запросах, я получил следующие результаты.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
mysql> EXPLAIN select * from Device where phoneNumber = 5107357058 ; +----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+ | 1 | SIMPLE | Device | ALL | phoneNumber,idx_Device_phoneNumber | NULL | NULL | NULL | 6482116 | Using where | +----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+ 1 row in set ( 0.00 sec) mysql> EXPLAIN select * from Device where phoneNumber = '5107357058' ; +----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+ | 1 | SIMPLE | Device | ref | phoneNumber,idx_Device_phoneNumber | phoneNumber | 258 | const | 2 | Using where | +----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+ 1 row in set ( 0.00 sec) |
EXPLAIN
дает вам другой атрибут запроса. При анализе запроса вы должны позаботиться о следующем атрибуте.
-
possible_keys :
показывает, что индексы применяются к запросу -
key :
какой ключ использовать, чтобы найти запись. Значения NULL показывают, что ключ не использовался для запроса и поиска SQL линейно, что в итоге занимает много времени. -
rows :
SQL-запрос с меньшим количеством строк результатов, эффективен. Всегда следует пытаться улучшить запрос и избегать использования общего запроса. Производительность запроса очень очевидна при выполнении большого количества записей. -
type :
is «Тип соединения».Ref
означает, что все строки с соответствующими значениями индекса считываются из таблицы;All
означает полное сканирование таблицы.
Два выхода EXPLAIN ясно указывают на тонкие различия. В последнем запросе используется string
правильным типом данных, в качестве ключа используется phoneNumber и проверяется только две строки. В то время как первый использует в запросе целое число, отличающееся типом данных, и, следовательно, SQL
преобразуется в целочисленное значение в строковое значение и сравнивается с каждой записью, представленной в этой таблице. Это приводит к NULL
качестве ключа и 6482116 в качестве вывода строки. Вы также можете видеть, что более поздним значением типа запроса является ref
а предыдущим значением типа запроса является All
, что ясно указывает на то, что первый является неправильным запросом.
Ссылка: Отладка SQL-запроса от нашего партнера по JCG Ракеша Кусата в блоге Code4Reference .