персональный технический блогwww.zhenganwen.top
План этой статьи
окрестности
-
win10-64
-
MySQL Community Server 5.7.1
mysqld –version
Видимая версия версии
Порядок выполнения SQL
рукописный приказ
Мы можем свести формат, которому следует следовать при написании SQL вручную, следующим образом:
select distinct
<select_list>
from
<left_table>
<join_type> join <right_table> on
<join_condition>
where
<where_condition>
group by
<group_by_list>
having
<having_condition>
order by
<order_by_condition>
limit <offset>,<rows>
-
distinct
, используемый для дедупликации набора результатов из запроса (если найдено несколько результатов с одинаковым значением столбца, будет учитываться только один результат) -
join
, Запрос таблицы ассоциации, если два набора как две таблицы, это может иметь эффект 7 различных запросов (описанных в следующем разделе). -
group by
, Часто используется в сочетании с агрегатными функциями, результирующий набор с одним или несколькими столбцами перед общим значением пакета. -
having
, часто используемый в сочетании с агрегатными функциями, чтобы компенсироватьwhere
Функции нельзя использовать в условиях -
order by
, отсортировать по какому-либо критерию, объединитьasc/desc
Реализовать восходящий нисходящий порядок -
limit
, если за ним следует целое числоn
перед возвращениемn
результат; если за ним следуют два целых числаm,n
это значит вернутьm
после результатаn
результаты (за исключениемm
Результаты)
Порядок разбора движка MySQL
Когда мы отправляем операторы SQL в службу MySQL, порядок разбора и выполнения обычно следующий:
from
<left_table>
on
<join_condition>
<join_type> join
<right_table>
where
<where_condition>
group by
<group_by_list>
having
<having_condition>
select
<select_list>
order by
<order_by_condition>
limit
offset,rows
Понимание этого обеспечивает основу для последующего анализа плана выполнения SQL.
Семь способов присоединиться
Далее мы создаем таблицу отделовtbl_dept
и таблица сотрудниковtbl_emp
Реализуйте вышеперечисленные 7 способов один за другим:
- Таблица отдела: первичный ключ
id
,Название отделаdeptName
, этаж отделаlocAdd
mysql> CREATE TABLE `tbl_dept` (
-> `id` INT(11) NOT NULL AUTO_INCREMENT,
-> `deptName` VARCHAR(30) DEFAULT NULL,
-> `locAdd` VARCHAR(40) DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
- таблица сотрудников: первичный ключ
id
,Имяname
, отделениеdeptId
mysql> CREATE TABLE `tbl_emp` (
-> `id` INT(11) NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(20) DEFAULT NULL,
-> `deptId` INT(11) DEFAULT NULL,
-> PRIMARY KEY (`id`),
-> KEY `fk_dept_id` (`deptId`)
-> #CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `tbl_dept` (`id`)
-> ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Вставьте некоторые тестовые данные:
mysql> INSERT INTO tbl_dept(deptName,locAdd) VALUES('技术部',11);
Query OK, 1 row affected (0.07 sec)
mysql> INSERT INTO tbl_dept(deptName,locAdd) VALUES('美工部',12);
Query OK, 1 row affected (0.08 sec)
mysql> INSERT INTO tbl_dept(deptName,locAdd) VALUES('总裁办',13);
Query OK, 1 row affected (0.06 sec)
mysql> INSERT INTO tbl_dept(deptName,locAdd) VALUES('人力资源',14);
Query OK, 1 row affected (0.11 sec)
mysql> INSERT INTO tbl_dept(deptName,locAdd) VALUES('后勤组',15);
Query OK, 1 row affected (0.10 sec)
mysql> insert into tbl_emp(name,deptId) values('jack',1);
Query OK, 1 row affected (0.11 sec)
mysql> insert into tbl_emp(name,deptId) values('tom',1);
Query OK, 1 row affected (0.08 sec)
mysql> insert into tbl_emp(name,deptId) values('alice',2);
Query OK, 1 row affected (0.08 sec)
mysql> insert into tbl_emp(name,deptId) values('john',3);
Query OK, 1 row affected (0.13 sec)
mysql> insert into tbl_emp(name,deptId) values('faker',4);
Query OK, 1 row affected (0.10 sec)
mysql> insert into tbl_emp(name) values('mlxg');
Query OK, 1 row affected (0.13 sec)
mysql> select * from tbl_dept;
+----+----------+--------+
| id | deptName | locAdd |
+----+----------+--------+
| 1 | 技术部 | 11 |
| 2 | 美工部 | 12 |
| 3 | 总裁办 | 13 |
| 4 | 人力资源 | 14 |
| 5 | 后勤组 | 15 |
+----+----------+--------+
5 rows in set (0.00 sec)
mysql> select * from tbl_emp;
+----+-------+--------+
| id | name | deptId |
+----+-------+--------+
| 1 | jack | 1 |
| 2 | tom | 1 |
| 3 | alice | 2 |
| 4 | john | 3 |
| 5 | faker | 4 |
| 7 | ning | NULL |
| 8 | mlxg | NULL |
+----+-------+--------+
7 rows in set (0.00 sec)
Связь между двумя таблицами показана на рисунке:
1. Левое соединение (уникальное + общее AB)
Запросите все отделы и количество сотрудников в каждом отделе:
mysql> select t1.id,t1.deptName,count(t2.name) as emps from tbl_dept t1 left join tbl_emp t2 on t2.deptId=t1.id group by deptName order by id;
+----+----------+------+
| id | deptName | emps |
+----+----------+------+
| 1 | 技术部 | 2 |
| 2 | 美工部 | 1 |
| 3 | 总裁办 | 1 |
| 4 | 人力资源 | 1 |
| 5 | 后勤组 | 0 |
+----+----------+------+
5 rows in set (0.00 sec)
2. Правое соединение (B уникальный + AB общий)
Опросите всех сотрудников и их отделы:
mysql> select t2.id,t2.name,t1.deptName from tbl_dept t1 right join tbl_emp t2 on t2.deptId=t1.id;
+----+-------+----------+
| id | name | deptName |
+----+-------+----------+
| 1 | jack | 技术部 |
| 2 | tom | 技术部 |
| 3 | alice | 美工部 |
| 4 | john | 总裁办 |
| 5 | faker | 人力资源 |
| 7 | ning | NULL |
| 8 | mlxg | NULL |
+----+-------+----------+
7 rows in set (0.04 sec)
3. Внутреннее соединение (совместное с AB)
Запросите данные, общие для двух таблиц:
mysql> select deptName,t2.name empName from tbl_dept t1 inner join tbl_emp t2 on t1.id=t2.deptId;
+----------+---------+
| deptName | empName |
+----------+---------+
| 技术部 | jack |
| 技术部 | tom |
| 美工部 | alice |
| 总裁办 | john |
| 人力资源 | faker |
+----------+---------+
4. Уникальный
То есть на основании (уникальный + AB общий) можно исключить B (черезb.id is null
может быть достигнут):
mysql> select a.deptName,b.name empName from tbl_dept a left join tbl_emp b on a.id=b.deptId where b.id is null;
+----------+---------+
| deptName | empName |
+----------+---------+
| 后勤组 | NULL |
+----------+---------+
5. Уникальный для Б
То же, что (уникально для A):
mysql> select a.name empName,b.deptName from tbl_emp a left join tbl_dept b on a.deptId=b.id where b.id is null;
+---------+----------+
| empName | deptName |
+---------+----------+
| ning | NULL |
| mlxg | NULL |
+---------+----------+
6. Уникальный + B уникальный
использоватьunion
Объедините (A уникальный) и (B уникальный) вместе:
mysql> select a.deptName,b.name empName from tbl_dept a left join tbl_emp b on a.id=b.deptId where b.id is null union select b.deptName,a.name emptName from tbl_emp a left join tbl_dept b on a.deptId=b.id where b.id is null;
+----------+---------+
| deptName | empName |
+----------+---------+
| 后勤组 | NULL |
| NULL | ning |
| NULL | mlxg |
+----------+---------+
7. Уникальный + AB публичный + B уникальный
использоватьunion
(съемный) союз (А уникальный + АВ публичный) и (Б уникальный + АВ публичный)
mysql> select a.deptName,b.name empName from tbl_dept a left join tbl_emp b on a.id=b.deptId union select a.deptName,b.name empName from tbl_dept a right join tbl_emp b on a.id=b.deptId;
+----------+---------+
| deptName | empName |
+----------+---------+
| 技术部 | jack |
| 技术部 | tom |
| 美工部 | alice |
| 总裁办 | john |
| 人力资源 | faker |
| 后勤组 | NULL |
| NULL | ning |
| NULL | mlxg |
+----------+---------+
Индексирование и обработка данных
Что такое индекс?
Индекс — это структура данных, которая при вставке записи извлекает значения поля (индексируемого поля) из записи как элементы структуры данных, а элементы в структуре данных — это При поиске записей по индексированным полям, эффективность поиска можно повысить с помощью бинарного поиска, кроме того, каждый элемент также имеет указатель на запись, которой он принадлежит (записи таблицы базы данных обычно хранятся на диске), поэтому связь между индексом и таблицей базы данных может быть изменена. можно сравнить со словарем Связь между оглавлением и текстом, а также размер оглавления (место хранения, занимаемое указателем) очень малы.
В базе данных обычно используемой структурой данных индекса является BTree (также известная как B-Tree, то есть дерево баланса, многостороннее сбалансированное дерево поиска. Бинарное дерево поиска со сбалансированным деревом поиска является особым случаем).
Почему это быстро после индексации?
Индекс представляет собой сводку больших текстовых данных, объем данных небольшой, и в нем можно выполнять двоичный поиск. Таким образом, когда мы ищем по проиндексированному полю: во-первых, данные таблицы становятся данными индекса (количество искомых данных значительно сокращается); во-вторых, данные индекса организованы упорядоченно, а время поиска сложность линейнаO(N)
сталO(logN)
(Это значительно и означает линейное2^32
Эта операция оптимизирована в32
операции).
Общие типы индексов MySQL
- индекс первичного ключа (
primary key
), может применяться только к одному полю (столбцу), и значение поля не может бытьnull
и не может быть повторен. - уникальный индекс (
unique key
), может применяться только к одному полю, а значение поля может бытьnull
но не повторять - Обыкновенный индекс (
key
), которые могут воздействовать на одно или несколько полей без ограничений на значения полей. Когда одно поле индексируется, оно называется индексом с одним значением, а когда несколько полей индексируются одновременно, это называется составным индексом (сочетание извлечения нескольких значений поля).
Тестирование уникальных индексов на неповторяемость и доступностьnull
:
mysql> create table `student` (
-> `id` int(10) not null auto_increment,
-> `stuId` int(32) default null,
-> `name` varchar(100) default null,
-> primary key(`id`),
-> unique key(`stuId`)
-> ) engine=innodb auto_increment=1 default charset=utf8;
mysql> insert into student(stuId,name) values('123456789','jack');
Query OK, 1 row affected (0.10 sec)
mysql> insert into student(stuId,name) values('123456789','tom');
ERROR 1062 (23000): Duplicate entry '123456789' for key 'stuId'
mysql> insert into student(stuId,name) values(null,'tom');
Query OK, 1 row affected (0.11 sec)
Управление индексами
создать индекс
-
Создать индекс при создании таблицы (DDL)
mysql> create table `student` ( -> `id` int(10) not null auto_increment, -> `stuId` int(32) default null, -> `name` varchar(100) default null, -> primary key(`id`), -> unique key(`stuId`) -> ) engine=innodb auto_increment=1 default charset=utf8;
-
Создайте оператор индекса:
create [unique] index <index_name> on <table_name>(<col1>,<col2>...)
mysql> create index idx_name on student(name); Query OK, 0 rows affected (0.44 sec) Records: 0 Duplicates: 0 Warnings: 0
-
Оператор изменения структуры таблицы:
alter table <table_name> add [unique] index <index_name> on (<col1>,<col2>....)
mysql> drop index idx_name on student; Query OK, 0 rows affected (0.27 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table student add index idx_name(name); Query OK, 0 rows affected (0.32 sec) Records: 0 Duplicates: 0 Warnings: 0
падение индекса
drop index <index_name> on <table_name>
индекс просмотра
SHOW INDEX FROM <table_name>
План выполнения SQL — объяснение
использоватьEXPLAIN
Ключевые слова могут имитировать оптимизатор для выполнения оператора SQL-запроса, чтобы знать, как MySQL обрабатывает ваш оператор SQL. Проанализируйте структуру запроса или таблицы на наличие узких мест в производительности.
что ты можешь сделать
пройти черезEXPLAIN
Проанализируйте следующие характеристики при выполнении инструкции SQL:
- Порядок чтения таблицы (когда задействовано несколько таблиц)
- Тип операции операции чтения данных
- Какие индексы можно использовать
- Какие индексы используются на самом деле
- ссылки между таблицами
- Сколько строк в таблице запрашивается оптимизатором
Как играть
Формат:explain <SQL语句>
:
разбор заголовка
id
Порядковый номер запроса на выборку, который содержит набор чисел, указывающих порядок, в котором предложение выбора или таблица операций выполняются в запросе. в соответствии сid
Являются ли они одинаковыми, можно разделить на следующие три ситуации:
-
всех записей
id
такой же как:Затем три записи в приведенной выше таблице выполняются в порядке сверху вниз, например, порядок чтения таблицы следующий:
t1,t3,t2
. Порядок синтаксического анализа SQL, упомянутый в первом разделе, также можно проверить, сначалаfrom t1,t2,t3
Указывает, что таблица предназначена для данного запроса, так как в ней нетjoin
, а потом анализироватьwhere
Приступая к чтению таблицы, стоит отметить, что она не соответствуетwhere
Написано, но в обратном порядке, то есть на разборt1.other_column=''
Так что прочитайте таблицуt1
,Потомt1.id=t3.id
читать счетчикt3
,Наконецt1.id=t2.id
читать счетчикt2
. Порядок разбора следующий:from t1,t2,t3 where t1.other_column='', t1.id=t3.id, t1.id=t2.id select t2.*
-
всех записей
id
Отличие: для вложенных запросов будет увеличиваться порядковый номер идентификатора, чем больше значение идентификатора, тем выше приоритет и выполняться первым. как:Для многоуровневых вложенных запросов завод выполнения выше. Порядок анализа:
from t2 where t2.id= from t1 where t1.id= from t3 where t3.other_column='' select t3.id select t1.id select t2.*
посредством
12,8,4
Строка может знать, что последовательность поиска в таблицеt3,t1,t2
. -
запись в таблице
id
одинаковые, некоторые разные.id
Одинаковые записи следуют за выводом 1, разные – за выводом 2.Порядок разбора:
from ( from t3 where t3.other_column='' select t3.id ) s1, t2 #s1是衍生表 where s1.id=t2.id select t2.*
посредством
6,11
Из двух строк видно, что порядок чтения таблицыt3,s1,t2
select_type
Общие значения для этого столбца следующие:
-
SIMPLE, указывающий, что этот SQL простой
select
запрос, в запросе нет подзапроса илиunion
-
ПЕРВИЧНЫЙ, если запрос содержит какие-либо сложные части, самый внешний запрос помечается как
PRIMARY
-
ПОДЗАПРОС, в
select
илиwhere
Подзапросы, содержащиеся в списке -
ПРОИЗВОДНЫЙ, в
from
подзапросы в предложениях помечаются какDERIVED
(производное). MySQL будет рекурсивно выполнять эти подзапросы, помещая результаты во временную таблицу. -
Союз,
union
Правоselect
-
РЕЗУЛЬТАТ СОЮЗА,
union
результат
table
Имя таблицы, указывающее, о какой таблице идет речь, также может быть в виде:
-
<derivedN>
, указывая, что таблица является идентификатором записиN
Производная таблица -
<unionM,N
>, указывая, что таблица является идентификатором записиM
иN
обаunion
результат после
partition
Если включена стратегия секционирования таблицы, в этом поле отображается секция, в которой расположены записи, которые могут соответствовать запросу.
type
type показывает тип доступа, который является важным показателем.Результирующие значения расположены в порядке от лучшего к худшему: system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL.
-
system
,В таблице есть только одна строка записей(равно системной таблице), это специальный столбец типа const, который обычно не отображается, и на это также можно не обращать внимания -
const
,Указывает, что индекс найден один раз,const
для сравненияprimary key
илиunique key
. Потому что он соответствует только одному ряду данных, это быстро. Поместив первичный ключ в списке «Где» MySQL может преобразовать запрос в константуmysql> select * from student; +----+-----------+------+ | id | stuId | name | +----+-----------+------+ | 1 | 123456789 | jack | | 3 | NULL | tom | +----+-----------+------+
-
eq_ref
,Сканирование уникального индекса, для каждого ключа индекса ему соответствует только одна запись в таблице.Обычно встречается при сканировании первичного ключа или уникального индекса.Для каждой части данных в b найдите идентификатор и его эквивалент из индекса первичного ключа a
-
ref
,сканирование неуникального индекса,Возвращает все строки, соответствующие отдельному значению. По сути, индексированный доступ возвращает все строки, соответствующие одному значению, однако он может найти несколько совпадающих строк, поэтому он должен представлять собой сочетание поиска и сканирования. (Поиски упорядочены пополам, а сканирование линейно.)mysql> create table `person` ( -> `id` int(32) not null auto_increment, -> `firstName` varchar(30) default null, -> `lastName` varchar(30) default null, -> primary key(`id`), -> index idx_name (firstName,lastName) -> ) engine=innodb auto_increment=1 default charset=utf8;
Ищу людей по фамилии Чжан:
-
range
, который извлекает определенный диапазон строк в соответствии с порядком индекса, который обычно появляется вbetween、<、>、in
Поиск равных диапазонов -
index
, чтобы просмотреть индекс, просто прочитайте данные индекса.Из-за составного индекса
idx_name
Он основан на (firstName, lastName). Этот тип индекса может только гарантировать, что он упорядочен по первому столбцу (то есть firstName), когда он определен как целое. Когда firstName совпадает, он сортируется по lastName. Если столбцов больше двух, они сортируются по фамилии и т. д. То есть при поиске по фамилии нельзя использовать двоичный код, и можно выполнить только полное сканирование индекса. -
all
, полное сканирование таблицы, которое требует чтения данных таблицы с диска.
-
Примечание. Вообще говоря, необходимо убедиться, что запрос достигает не менее
range
уровень, желательноref
.
possible_keys
MySQL может использовать индексы для быстрого извлечения строк.
key
Индекс, фактически используемый при выполнении MySQL.
key_len
-
Указывает максимальное количество байтов на элемент в индексе, которое можно использовать для расчета длины индекса, используемого в запросе (подробнее о том, как рассчитать, будет сказано позже).
Более короткие длины лучше без потери точности.
-
Значение, отображаемое key_len, представляет собой максимально возможную длину поля индекса, а не фактическую длину, то есть key_len вычисляется в соответствии с определением таблицы, а не извлекается из таблицы.
Как рассчитать? Сначала нам нужно понять пространство, занимаемое типами данных MySQL:
-
Числовой тип
-
тип даты (
datetime
Длина поля типа 5 байт в MySQL 5.6, а длина поля 8 байт в 5.5) -
Тип строки
latin1
Закодированный символ занимает 1 байт,gbk
Закодированные символы занимают 2 байта,utf8
Закодированные символы занимают 3 байта.c1 char(10)
для каждой строки записейc1
Поле занимает фиксированные 10 байт;c2 varchar(10)
Не обязательно, если ряд данных имеетc2
Значение поля занимает всего 3 байта, тогда строка данныхc2
Поле на самом деле занимает 5 байт, потому что размер пространства, занимаемого этим типом поля, является переменным, поэтому необходимы дополнительные 2 байта для сохранения длины значения поля, и потому чтоvarchar
Максимальное количество байтов равно 65 535, поэтому значение поля занимает максимум 65 533 байта.следовательно,
- Если заранее известно, что данные, хранящиеся в поле, представляют собой фиксированное количество символов, то они будут использоваться первыми.
char
для экономии места для хранения. - установить как можно больше
not null
и установите значение по умолчанию на‘’
или0
- Если заранее известно, что данные, хранящиеся в поле, представляют собой фиксированное количество символов, то они будут использоваться первыми.
Демонстрируется индексом поля строкового типаkey_len
Процесс расчета (сutf8
пример кодирования):
-
Поле индекса
char
Тип +not null
:key_len
= Количество символов, объявленных в поле *3 (каждый символ в кодировке utf8 занимает 3 байта)mysql> create table test( -> id int(10) not null auto_increment, -> primary key(id) -> ) engine=innodb auto_increment=1 default charset=utf8; mysql> alter table test add c1 char(10) not null; mysql> create index idx_c1 on test(c1);
-
Поле индекса
char
тип + может бытьnull
:key_len
= количество символов в объявлении поля * 3 + 1 (один байт используется для указания того, является ли значение поляnull
)mysql> alter table test add c2 char(10) default null; mysql> create index idx_c2 on test(c2);
-
Поле индекса
varchar
+not null
,key_len
= Количество символов в объявлении поля * 3 + 2 (количество байтов, используемых для хранения значения поля)mysql> alter table test add c3 varchar(10) not null; mysql> create index idx_c3 on test(c3);
-
varchar
+ может бытьnull
,key_len
= Количество символов в объявлении поля * 3 + 2 + 1 (используется для определения того, является ли значение поляnull
)
По этому значению можно судить об использовании индекса, особенно при использовании составного индекса, чтобы определить, можно ли запрашивать несколько полей, составляющих составной индекс.
как:
mysql> desc person; +-----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+----------------+ | id | int(32) | NO | PRI | NULL | auto_increment | | firstName | varchar(30) | YES | MUL | NULL | | | lastName | varchar(30) | YES | | NULL | | +-----------+-------------+------+-----+---------+----------------+
В первом используется часть составного индекса, а во втором — все, что также упоминается в разделе о типе индекса и определяется порядком крайнего левого префикса (первый столбец при определении составного индекса).
ref
Показывает, какой столбец или константа сравнивается со столбцом индекса для извлечения строк из таблицы.
Как мы используем‘’
Получить строку в индексе.
rows
Основываясь на статистике таблицы и выборе индекса, приблизительно оцените количество строк, которые необходимо прочитать, чтобы найти нужную запись.
Extra
Содержит важную дополнительную информацию, которая не помещается в другие столбцы:
-
Using filesort
: Указывает, что mysql будет использовать внешний индекс для сортировки данных вместо чтения в порядке индекса в таблице. Операция сортировки в MySQL, которую нельзя выполнить с помощью индекса, называется «сортировкой файлов».mysql> explain select * from person order by lastName\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: person partitions: NULL type: index possible_keys: NULL key: idx_name key_len: 186 ref: NULL rows: 1 filtered: 100.00 Extra: Using index; Using filesort
использовать
\G
заменять;
Конец может привести к вертикальному отображению плана выполнения.mysql> explain select * from person order by firstName,lastName\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: person partitions: NULL type: index possible_keys: NULL key: idx_name key_len: 186 ref: NULL rows: 1 filtered: 100.00 Extra: Using index
-
Using temporary
: временная таблица используется для хранения промежуточных результатов.MySQL использует временные таблицы при агрегировании результатов запроса. распространенный в сортировкеorder by
и групповые запросыgroup by
.mysql> insert into person(firstName,lastName) values('张','三'); mysql> insert into person(firstName,lastName) values('李','三'); mysql> insert into person(firstName,lastName) values('王','三'); mysql> insert into person(firstName,lastName) values('李','明'); mysql> select lastName,count(lastName) from person group by lastName; +----------+-----------------+ | lastName | count(lastName) | +----------+-----------------+ | 三 | 3 | | 明 | 1 | +----------+-----------------+ mysql> explain select lastName,count(lastName) from person group by lastName\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: person partitions: NULL type: index possible_keys: idx_name key: idx_name key_len: 186 ref: NULL rows: 4 filtered: 100.00 Extra: Using index; Using temporary; Using filesort
-
Using index
: указывает, что используется соответствующая операция выбораИндекс покрытияИзбегайте доступа к строке данных таблицы (необходимо прочитать диск), эффективность хорошая! Если оба появляютсяUsing where
, указывающий, что индекс используется для поиска значения ключа индекса; если он не присутствует в то же времяUsing where
, что указывает на то, что индекс используется для чтения данных, а не для выполнения поиска.Покрытие индекса: Да
select
Столбец данных можно получить только из индекса, без чтения строки данных MySQL может использовать индекс для возвратаselect
Поля в списке, без необходимости снова читать файл данных по индексу, другими словами, столбец запроса должен быть покрыт построенным индексом.Если вы хотите использовать покрывающий индекс, обязательно обратите внимание
select
Удалить только список столбцов требуется, а неselect *
, так как если все поля индексируются вместе, файл индекса будет слишком большим, и производительность запросов снизится. -
Using where
: запрос используетсяwhere
утверждение -
Using join buffer
: используется кеш соединения -
Impossible where
:where
Значение предложения всегдаfalse
,какselect * from person where id=1 and id=2;
аннулирование индекса
При использованииexplain
Откройте для себя типы доступа при анализе плана выполнения SQLtype
заALL
или фактический используемый индексkey
заNULL
, это означает, что запрос не использует индекс и приводит к полному сканированию таблицы, чего нам нужно избегать. Ниже приведены некоторые принципы использования индексов:
1. Полное значение соответствует моему любимому
Индекс должен использоваться при поиске по индексному полю в соответствии с константой.
Сюда
2. Правило наилучшего левого префикса
При получении составного индекса необходимо следовать принципу, что левый префикс указывается первым.
mysql> alter table test add c5 varchar(10) default null, add c6 varchar(10) default null, add c7 varchar(10) default null;
mysql> create index idx_c5_c6_c7 on test(c5,c6,c7);
Индексы не используются, если нет столбца с левым префиксом:
mysql> explain select * from test where c6=''\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
mysql> explain select * from test where c6='' and c7=''\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
И пока крайний левый столбец префикса впереди, другие столбцы могут быть не в порядке, но лучше этого не делать (в соответствии с порядком столбцов, определенных составным индексом для достижения наилучшей эффективности ):
mysql> explain select * from test where c5='' and c7=''\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
partitions: NULL
type: ref
possible_keys: idx_c5_c6_c7
key: idx_c5_c6_c7
key_len: 33
ref: const
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from test where c5='' and c7='' and c6=''\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
partitions: NULL
type: ref
possible_keys: idx_c5_c6_c7
key: idx_c5_c6_c7
key_len: 99
ref: const,const,const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
Лучшей практикой является:
mysql> explain select * from test where c5=''\G
mysql> explain select * from test where c5='' and c6=''\G
mysql> explain select * from test where c5='' and c6='' and c7=''\G
3. Не добавляйте никаких операций к именам столбцов
Иногда мы выполняем вычисления, операции функций, автоматические и ручные преобразования типов для имен столбцов, что напрямую приводит к сбою индекса.
mysql> explain select * from person where left(firstName,1)='张'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: person
partitions: NULL
type: index
possible_keys: NULL
key: idx_name
key_len: 186
ref: NULL
rows: 4
filtered: 100.00
Extra: Using where; Using index
mysql> explain select * from person where firstName='张'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: person
partitions: NULL
type: ref
possible_keys: idx_name
key: idx_name
key_len: 93
ref: const
rows: 1
filtered: 100.00
Extra: Using index
Вышеупомянутые два SQL-запроса также используются для поиска человека по фамилии Чжан, но в имени столбцаfirstName
Использованиеleft
Функция разрешает тип доступаtype
отref
(сканирование неуникального индекса) сводится кindex
(полное сканирование индекса)
4. Механизм хранения не может использовать столбец справа от условия диапазона в индексе.
Это видно из приведенного выше рисункаc6 > ‘a’
колонка справаc7
Хотя и составной индексidx_c5_c6_c7
, но поkey_len:66
Видимо не использовали. Как правило, чем выше использование индекса, тем выше эффективность поиска.
5. Максимально используйте покрытие индекса
Старайтесь поддерживать согласованность столбца запроса и столбца индекса, чтобы можно было избежать доступа к строке данных и напрямую возвращать данные индекса. избегать использованияselect *
если только данных таблицы очень мало, т.к.select *
Существует высокая вероятность доступа к строкам данных.
Using index
Указывает, что произошла перезапись индекса
6. Использование != или может привести к сбою индекса
7, не нуль также влияет на индекс
какname
Определение неnot null
Там не будет индексироваться без использования.
8. Например, запуск с подстановочным знаком приведет к сбою индекса.
like
заявление с подстановочным знаком%
Неспособность воспользоваться преимуществами индекса в начале приводит к полному сканированию индекса, а простое окончание с подстановочным знаком — нет.
9. Пока в столбце соединения нет индекса, полное сканирование таблицы
10. Пока нет индекса для столбцов с обеих сторон или, полное сканирование таблицы
11. Неверный индекс строки без одинарных кавычек
mysql> explain select * from staff where name=123;
Вирши:
Полное значение соответствует моему любимому, левый префикс будет следовать.
Ведущий старший брат не может умереть, а средний брат не может быть сломлен.
Меньше вычислений в столбце индекса, все недопустимо после диапазона.
LIKE процент самый правый, а индекс покрытия не пишет *.
Существует также ИЛИ, если нулевое значение не равно, и следует обратить внимание на правую часть ON.
Кавычки VAR не могут быть потеряны, и есть трюк с оптимизацией SQL.