Расширенный MySQL

MySQL

персональный технический блогwww.zhenganwen.top

План этой статьи

SQL高级

окрестности

Порядок выполнения 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

image

Понимание этого обеспечивает основу для последующего анализа плана выполнения SQL.

Семь способов присоединиться

image

Далее мы создаем таблицу отделов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)

Связь между двумя таблицами показана на рисунке:

image

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>

image

План выполнения SQL — объяснение

использоватьEXPLAINКлючевые слова могут имитировать оптимизатор для выполнения оператора SQL-запроса, чтобы знать, как MySQL обрабатывает ваш оператор SQL. Проанализируйте структуру запроса или таблицы на наличие узких мест в производительности.

что ты можешь сделать

пройти черезEXPLAINПроанализируйте следующие характеристики при выполнении инструкции SQL:

  • Порядок чтения таблицы (когда задействовано несколько таблиц)
  • Тип операции операции чтения данных
  • Какие индексы можно использовать
  • Какие индексы используются на самом деле
  • ссылки между таблицами
  • Сколько строк в таблице запрашивается оптимизатором

Как играть

Формат:explain <SQL语句>:

image

разбор заголовка

id

Порядковый номер запроса на выборку, который содержит набор чисел, указывающих порядок, в котором предложение выбора или таблица операций выполняются в запросе. в соответствии сidЯвляются ли они одинаковыми, можно разделить на следующие три ситуации:

  • всех записейidтакой же как:

    image

    Затем три записи в приведенной выше таблице выполняются в порядке сверху вниз, например, порядок чтения таблицы следующий: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Отличие: для вложенных запросов будет увеличиваться порядковый номер идентификатора, чем больше значение идентификатора, тем выше приоритет и выполняться первым. как:

    image

    Для многоуровневых вложенных запросов завод выполнения выше. Порядок анализа:

    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.

    image

    Порядок разбора:

    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

    image

  • ПЕРВИЧНЫЙ, если запрос содержит какие-либо сложные части, самый внешний запрос помечается какPRIMARY

    image

  • ПОДЗАПРОС, в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 может преобразовать запрос в константу

    image

    mysql> select * from student;
    +----+-----------+------+
    | id | stuId     | name |
    +----+-----------+------+
    |  1 | 123456789 | jack |
    |  3 |      NULL | tom  |
    +----+-----------+------+
    

    image

    • eq_ref,Сканирование уникального индекса, для каждого ключа индекса ему соответствует только одна запись в таблице.Обычно встречается при сканировании первичного ключа или уникального индекса.

      image

      Для каждой части данных в 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;
      

      Ищу людей по фамилии Чжан:

      image

    • range, который извлекает определенный диапазон строк в соответствии с порядком индекса, который обычно появляется вbetween、<、>、inПоиск равных диапазонов

      image

    • index, чтобы просмотреть индекс, просто прочитайте данные индекса.

      1559474816109

      Из-за составного индексаidx_nameОн основан на (firstName, lastName). Этот тип индекса может только гарантировать, что он упорядочен по первому столбцу (то есть firstName), когда он определен как целое. Когда firstName совпадает, он сортируется по lastName. Если столбцов больше двух, они сортируются по фамилии и т. д. То есть при поиске по фамилии нельзя использовать двоичный код, и можно выполнить только полное сканирование индекса.

    • all, полное сканирование таблицы, которое требует чтения данных таблицы с диска.

Примечание. Вообще говоря, необходимо убедиться, что запрос достигает не менееrangeуровень, желательноref.

possible_keys

MySQL может использовать индексы для быстрого извлечения строк.

key

Индекс, фактически используемый при выполнении MySQL.

key_len

  • Указывает максимальное количество байтов на элемент в индексе, которое можно использовать для расчета длины индекса, используемого в запросе (подробнее о том, как рассчитать, будет сказано позже).

    Более короткие длины лучше без потери точности.

  • Значение, отображаемое key_len, представляет собой максимально возможную длину поля индекса, а не фактическую длину, то есть key_len вычисляется в соответствии с определением таблицы, а не извлекается из таблицы.

Как рассчитать? Сначала нам нужно понять пространство, занимаемое типами данных MySQL:

  • Числовой тип

    image

  • тип даты (datetimeДлина поля типа 5 байт в MySQL 5.6, а длина поля 8 байт в 5.5)

    image

  • Тип строки

    1559475897645

    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);
    

    image

  • Поле индекса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);
    

    1559477148209

  • Поле индекса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);
    

    image

  • 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    |                |
+-----------+-------------+------+-----+---------+----------------+

image

image

В первом используется часть составного индекса, а во втором — все, что также упоминается в разделе о типе индекса и определяется порядком крайнего левого префикса (первый столбец при определении составного индекса).

ref

Показывает, какой столбец или константа сравнивается со столбцом индекса для извлечения строк из таблицы.

image

Как мы используем‘’Получить строку в индексе.

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. Полное значение соответствует моему любимому

Индекс должен использоваться при поиске по индексному полю в соответствии с константой.

image

Сюда

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. Механизм хранения не может использовать столбец справа от условия диапазона в индексе.

image

Это видно из приведенного выше рисункаc6 > ‘a’колонка справаc7Хотя и составной индексidx_c5_c6_c7, но поkey_len:66Видимо не использовали. Как правило, чем выше использование индекса, тем выше эффективность поиска.

5. Максимально используйте покрытие индекса

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

image

Using indexУказывает, что произошла перезапись индекса

6. Использование != или может привести к сбою индекса

image

7, не нуль также влияет на индекс

image

image

какnameОпределение неnot nullТам не будет индексироваться без использования.

8. Например, запуск с подстановочным знаком приведет к сбою индекса.

likeзаявление с подстановочным знаком%Неспособность воспользоваться преимуществами индекса в начале приводит к полному сканированию индекса, а простое окончание с подстановочным знаком — нет.

image

9. Пока в столбце соединения нет индекса, полное сканирование таблицы

image

10. Пока нет индекса для столбцов с обеих сторон или, полное сканирование таблицы

image

11. Неверный индекс строки без одинарных кавычек

mysql> explain select * from staff where name=123;

Вирши:

Полное значение соответствует моему любимому, левый префикс будет следовать.

Ведущий старший брат не может умереть, а средний брат не может быть сломлен.

Меньше вычислений в столбце индекса, все недопустимо после диапазона.

LIKE процент самый правый, а индекс покрытия не пишет *.

Существует также ИЛИ, если нулевое значение не равно, и следует обратить внимание на правую часть ON.

Кавычки VAR не могут быть потеряны, и есть трюк с оптимизацией SQL.