51
СУБД Лекция 7 Павел Щербинин

СУБД осень 2012 лекция 7

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: СУБД осень 2012 лекция 7

СУБДЛекция 7

Павел Щербинин

Page 2: СУБД осень 2012 лекция 7

Профилирование

• К каким данным MySQL обращается чаще всего

• Какие типы запросов MySQL выполняет чаще всего

• В каких состояниях преимущественно находятся потоки (threads) MySQL

• Какие подсистемы MySQL чаще всего использует для выполнения запросов

• Какие виды обращения к данным встречаются наиболее часто

• Сколько различных видов действий, например просмотра индексов, выполняет MySQL

Page 3: СУБД осень 2012 лекция 7

Протоколирование запросов

Общий журналlog = <имя_файла>

Журнал медленных запросовlog-slow-queries = <имя_файла>long_query_time = 2log-queries-not-using-indexeslog-slow-admin-statements

# Time: 121018 9:47:00# User@Host: root[root] @ localhost []# Query_time: 0.000652 Lock_time: 0.000109 Rows_sent: 50# Rows_examined: 3268SELECT ...

Page 4: СУБД осень 2012 лекция 7

Протоколирование запросов

• Таблица могла быть заблокирована, поэтому запрос был вынужден ждать. Величина Lock_time показывает, как долго запрос ждал освобождения блокировки.

• Данные или индексы могли к тому моменту еще отсутствовать в кэше. Это обычный случай, когда сервер MySQL только запущен или не настроен должным образом.

• Мог идти ночной процесс резервного копирования, из-за чего все операции дискового ввода/вывода замедлялись.

• Сервер мог обрабатывать в тот момент другие запросы, поэтому данный выполнялся медленнее.

Page 5: СУБД осень 2012 лекция 7

Протоколирование запросов

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

Запросы, больше всего нагружающие серверИщите запросы, которые потребляют большую часть времени сервера. Напомним, что короткие запросы, выполняемые очень часто, тоже могут занимать много времени.

Новые запросыИщите запросы, которых вчера не было в первой сотне, а сегодня они появились. Это могут быть новые запросы или запросы, которые обычно выполнялись быстро, а теперь замедлились из-за изменившейся схемы индексации. Либо произошли еще какие-то изменения.

Page 6: СУБД осень 2012 лекция 7

Профилирование сервера

SHOW STATUSBytes_received и Bytes_sent

Количество байтов, соответственно полученных и отправленных сервером.

Com_*Команды, которые сервер выполняет

Created_*Временные таблицы и файлы, созданные во время выполнения запроса

Handler_*Операции подсистемы хранения

Select_*Различные типы планов выполнения операции соединения

Sort_*Разнообразная информация о сортировке

Page 7: СУБД осень 2012 лекция 7

Профилирование запросов

SET profiling = 1;

SELECT SQL_NO_CACHE `movie`.`mID`, COUNT(*)FROM `movie`

INNER JOIN `rating` USING(`mID`)GROUP BY `movie`.`mID`ORDER BY COUNT(*) DESC;

SHOW PROFILES\G******************** 1. row *********************Query_ID: 1Duration: 0.02596900Query: SELECT …

Page 8: СУБД осень 2012 лекция 7

EXPLAIN

• EXPLAIN ничего не говорит о том, как влияют на запрос триггеры, хранимые и пользовательские (UDF) функции.

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

• Она ничего не говорит об оптимизациях, которые MySQL производит уже на этапе выполнения запроса.

• Часть отображаемой статистической информации – всего лишь оценка, иногда очень неточная.

• Она не показывает все, что можно было бы сообщить о плане выполнения запроса

• Она не делает различий между некоторыми операциями, называя их одинаково.

Page 9: СУБД осень 2012 лекция 7

Столбцы EXPLAINid

EXPLAIN SELECT (SELECT 1 FROM sakila.actor LIMIT 1) FROM sakila.filmid select_type table

1PRIMARY film2SUBQUERY actor

EXPLAIN SELECT film_id FROM (SELECT film_id FROM sakila.film) AS der;id select_type table

1PRIMARY <derived2>2DERIVED film

EXPLAIN SELECT 1 UNION ALL SELECT 1;id select_type table

1PRIMARY NULL2UNION NULL

NULL UNION RESULT <union1,2>

Page 10: СУБД осень 2012 лекция 7

Столбцы EXPLAINselect_type

PRIMARYСамый внешний запрос

SUBQUERYЗапрос SELECT, который содержится в подзапросе, находящемся во фразе SELECT (иными словами, не во фразе FROM

DERIVEDЗначение DERIVED означает, что данный запрос SELECT является подзапросом во фразе FROM.

UNIONВторой и последующий запросы SELECT, входящие в объединениеUNION, помечаются признаком UNION.

UNION RESULTЗапрос SELECT, применяемый для выборки результатов из временнойтаблицы, созданной в ходе выполнения UNION.

Page 11: СУБД осень 2012 лекция 7

Столбцы EXPLAINtable

EXPLAIN SELECT film.film_idFROM sakila.film

INNER JOIN sakila.film_actor USING(film_id)INNER JOIN sakila.actor USING(actor_id);

id select_type table1SIMPLE actor1SIMPLE film_actor1SIMPLE film

Page 12: СУБД осень 2012 лекция 7

Столбцы EXPLAINtable

EXPLAIN SELECT actor_id,(SELECT 1 FROM sakila.film_actor WHERE film_actor.actor_id = der_1.actor_id LIMIT 1)FROM (

SELECT actor_idFROM sakila.actor LIMIT 5

) AS der_1UNION ALLSELECT film_id,(SELECT @var1 FROM sakila.rental LIMIT 1)FROM (

SELECT film_id,(SELECT 1 FROM sakila.store LIMIT 1)FROM sakila.film LIMIT 5

) AS der_2;id select_type table

1PRIMARY <derived3>3DERIVED actor2DEPENDENT SUBQUERY film_actor4UNION <derived6>6DERIVED film7SUBQUERY store5UNCACHEABLE SUBQUERY rental

NULL UNION RESULT <union1,4>

Page 13: СУБД осень 2012 лекция 7

Столбцы EXPLAINtype

ALLЭтот подход обычно называют сканированием таблицы.

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

rangeПросмотр диапазона – это ограниченная форма сканирования индекса. Просмотр начинается в определенной точке индекса и возвращает строки в некотором диапазоне значений.

refЭто доступ по индексу (иногда он называется поиском по индексу (index lookup)), в результате которого возвращаются строки, соответствующие единственному заданному значению.

eq_refЭто поиск по индексу в случае, когда MySQL точно знает, что будет возвращено не более одного значения.

const, systemЭти типы доступа MySQL применяет, когда в процессе оптимизации какую-то часть запроса можно преобразовать в константу.

NULLЭтот метод означает, что MySQL сумела разрешить запрос на фазе оптимизации, так что в ходе выполнения вообще не потребуется обращаться к таблице или индексу.

Page 14: СУБД осень 2012 лекция 7

Столбцы EXPLAINpossible_keys, key

EXPLAIN SELECT actor_id, film_id FROM sakila.film_actor\G

************************* 1. row *************************id: 1select_type: SIMPLEtable: film_actortype: indexpossible_keys: NULLkey: idx_fk_film_idkey_len: 2ref: NULLrows: 5143Extra: Using index

Page 15: СУБД осень 2012 лекция 7

Столбцы EXPLAINkey_len

EXPLAIN SELECT actor_id, film_id FROM sakila.film_actor WHERE actor_id=4;

...| type | possible_keys | key | key_len |...

...| ref | PRIMARY | PRIMARY | 2 |...

Page 16: СУБД осень 2012 лекция 7

Столбцы EXPLAINkey_len

EXPLAIN SELECT actor_id, film_id FROM sakila.film_actor WHERE actor_id=4;

...| type | possible_keys | key | key_len |...

...| ref | PRIMARY | PRIMARY | 2 |...

CREATE TABLE t (a char(3) NOT NULL,b int(11) NOT NULL,c char(1) NOT NULL,PRIMARY KEY (a,b,c)

) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

EXPLAIN SELECT a FROM t WHERE a=’sak’ AND b = 112;

Page 17: СУБД осень 2012 лекция 7

Столбцы EXPLAINkey_len

EXPLAIN SELECT actor_id, film_id FROM sakila.film_actor WHERE actor_id=4;

...| type | possible_keys | key | key_len |...

...| ref | PRIMARY | PRIMARY | 2 |...

CREATE TABLE t (a char(3) NOT NULL,b int(11) NOT NULL,c char(1) NOT NULL,PRIMARY KEY (a,b,c)

) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

EXPLAIN SELECT a FROM t WHERE a=’sak’ AND b = 112;

... |type | possible_keys | key | key_len |...

... | ref | PRIMARY | PRIMARY | 13 |...

Page 18: СУБД осень 2012 лекция 7

Столбцы EXPLAINref

EXPLAIN SELECT STRAIGHT_JOIN f.film_idFROM sakila.film AS f

INNER JOIN sakila.film_actor AS faON f.film_id=fa.film_id AND fa.actor_id = 1

INNER JOIN sakila.actor AS a USING(actor_id);

...| table |...| key | key_len | ref |...

...| a |...| PRIMARY | 2 | const |...

...| f |...| idx_fk_language_id | 1 | NULL |...

...| fa |...| PRIMARY | 4 | const,sakila.f.film_id |...

Page 19: СУБД осень 2012 лекция 7

Столбцы EXPLAINrows

EXPLAIN SELECT f.film_idFROM sakila.film AS f

INNER JOIN sakila.film_actor AS fa USING(film_id)INNER JOIN sakila.actor AS a USING(actor_id);

...| rows |...

...| 200 |...

...| 13 |...

...| 1 |...

Page 20: СУБД осень 2012 лекция 7

Столбцы EXPLAINextra

Using indexОзначает, что MySQL воспользуется покрывающим индексом, чтобы избежать доступа к самой таблице.

Using whereОзначает, что сервер произведет дополнительную фильтрацию строк, отобранных подсистемой хранения.

Using temporaryОзначает, что MySQL будет применять временную таблицу для сортировки результатов запроса.

Using filesortОзначает, что MySQL прибегнет к обычной сортировке для упорядочения результатов, а не станет читать строки из таблицы в порядке, задаваемом индексом.

range checked for each recordОзначает, что подходящего индекса не нашлось, поэтому сервер будет заново искать индекс при обработке каждой строки в операции соединения.

Page 21: СУБД осень 2012 лекция 7

EXPLAIN for UPDATE

UPDATE sakila.actorINNER JOIN sakila.film_actor USING (actor_id)

SET actor.last_update=film_actor.last_update;

Page 22: СУБД осень 2012 лекция 7

EXPLAIN for UPDATE

UPDATE sakila.actorINNER JOIN sakila.film_actor USING (actor_id)

SET actor.last_update=film_actor.last_update;

EXPLAIN SELECT film_actor.actor_idFROM sakila.actor

INNER JOIN sakila.film_actor USING (actor_id)\G

***** 1. row *****id: 1select_type: SIMPLEtable: actortype: indexpossible_keys: PRIMARYkey: PRIMARYkey_len: 2ref: NULLrows: 200Extra: Using index***** 2. row *****id: 1select_type: SIMPLEtable: film_actortype: refpossible_keys: PRIMARYkey: PRIMARYkey_len: 2ref: sakila.actor.actor_idrows: 13Extra: Using index

Page 23: СУБД осень 2012 лекция 7

EXPLAIN for UPDATE

UPDATE sakila.actorINNER JOIN sakila.film_actor USING (actor_id)

SET actor.last_update=film_actor.last_update;

EXPLAIN SELECT film_actor.last_update, actor.last_updateFROM sakila.actor

INNER JOIN sakila.film_actor USING (actor_id)\G

***** 1. row *****id: 1select_type: SIMPLEtable: actortype: ALLpossible_keys: PRIMARYkey: NULLkey_len: NULLref: NULLrows: 200Extra:***** 2. row *****id: 1select_type: SIMPLEtable: film_actortype: refpossible_keys: PRIMARYkey: PRIMARYkey_len: 2ref: sakila.actor.actor_idrows: 13Extra:

Page 24: СУБД осень 2012 лекция 7

Стратегия индексированияИзоляция столбца

SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

SELECT ... WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <= 10;

Page 25: СУБД осень 2012 лекция 7

Стратегия индексированияИзоляция столбца

SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

SELECT ... WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <= 10;

SELECT ... WHERE date_col >= DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY);

Page 26: СУБД осень 2012 лекция 7

Стратегия индексированияИзоляция столбца

SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

SELECT ... WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <= 10;

SELECT ... WHERE date_col >= DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY);

SELECT ... WHERE date_col >= DATE_SUB(‘2008-01-17’, INTERVAL 10 DAY);

Page 27: СУБД осень 2012 лекция 7

Стратегия индексированияКластерные индексы

Page 28: СУБД осень 2012 лекция 7

Стратегия индексированияКластерные индексы (+)

• Вы можете хранить связанные данные рядом.

• Быстрый доступ к данным. Кластерный индекс хранит и индекс, и данные вместе в одной B-Tree структуре, поэтому извлечение строк из кластерного индекса обычно происходит быстрее, чем сопоставимый поиск в некластерном индексе.

• Использующие покрывающие индексы запросы могут получить значение первичного ключа из листового узла.

Page 29: СУБД осень 2012 лекция 7

Стратегия индексированияКластерные индексы (-)• Если данные помещаются в памяти, то порядок доступа к ним не имеет

значения, и тогда кластерные индексы не принесут большой пользы.• Если вы загружаете большое количество данных в другом порядке, то по

окончании загрузки имеет смысл реорганизовать таблицу с помощью команды OPTIMIZE TABLE.

• Обновление столбцов кластерного индекса обходится дорого, поскольку InnoDB вынуждена перемещать каждую обновленную строку в новое место.

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

• Полное сканирование кластерных таблиц может оказаться более медленным, особенно если строки упакованы менее плотно или хранятся непоследовательно из-за расщепления страниц.

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

• Для доступа к данным по вторичному индексу требуется просмотр двух индексов вместо одного.

Page 30: СУБД осень 2012 лекция 7

Стратегия индексированияРазмещение данных в MyISAM

CREATE TABLE layout_test ( col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1), KEY(col2));

Page 31: СУБД осень 2012 лекция 7

Стратегия индексированияРазмещение данных в MyISAM

CREATE TABLE layout_test ( col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1), KEY(col2));

Page 32: СУБД осень 2012 лекция 7

Стратегия индексированияРазмещение данных в InnoDB

CREATE TABLE layout_test ( col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1), KEY(col2));

Page 33: СУБД осень 2012 лекция 7

Стратегия индексированияРазмещение данных в InnoDB

CREATE TABLE layout_test ( col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1), KEY(col2));

Page 34: СУБД осень 2012 лекция 7

Стратегия индексированияРазмещение данных

CREATE TABLE layout_test ( col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1), KEY(col2));

Page 35: СУБД осень 2012 лекция 7

Стратегия индексированияРазмещение данных

Page 36: СУБД осень 2012 лекция 7

Покрывающие индексы

• Записи индекса обычно компактнее полной строки, поэтому, если MySQL читает только индекс, то обращается к значительно меньшему объему данных.

• Индексы отсортированы по индексируемым значениям (по крайней мере, внутри страницы), поэтому для поиска по диапазону, характеризуемому большим объемом ввода/вывода, потребуется меньше операций обращения к диску.

• Большинство подсистем хранения кэширует индексы лучше, чем сами данные.

• Покрывающие индексы особенно полезны в случае таблиц InnoDB из-за кластерных индексов. Вторичные индексы InnoDB хранят значения первичного ключа строки в листовых узлах. Таким образом, вторичный индекс, который «покрывает» запрос, позволяет избежать еще одного поиска по первичному индексу.

Page 37: СУБД осень 2012 лекция 7

Покрывающие индексы

EXPLAIN SELECT store_id, film_id FROM sakila.inventory\G************************** 1. row **************************id: 1select_type: SIMPLEtable: inventorytype: indexpossible_keys: NULLkey: idx_store_id_film_idkey_len: 3ref: NULLrows: 4673Extra: Using index

Page 38: СУБД осень 2012 лекция 7

Покрывающие индексы

EXPLAIN SELECT actor_id, last_nameFROM sakila.actor WHERE last_name = ‘HOPPER’\G************************** 1. row **************************id: 1select_type: SIMPLEtable: actortype: refpossible_keys: idx_actor_last_namekey: idx_actor_last_namekey_len: 137ref: constrows: 2Extra: Using where; Using index

Page 39: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date = ‘2005-05-25’ORDER BY inventory_id, customer_id\G************************** 1. row **************************type: refpossible_keys: rental_datekey: rental_daterows: 1Extra: Using where

Page 40: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date = ‘2005-05-25’ ORDER BY inventory_id DESC;

Page 41: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date = ‘2005-05-25’ ORDER BY inventory_id DESC, customer_id ASC;

Page 42: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date = ‘2005-05-25’ ORDER BY inventory_id, staff_id;

Page 43: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date > ‘2005-05-25’ ORDER BY rental_date, inventory_id;

Page 44: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date = ‘2005-05-25’ ORDER BY customer_id;

Page 45: СУБД осень 2012 лекция 7

Покрывающие индексы

CREATE TABLE rental (...PRIMARY KEY (rental_id),UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),KEY idx_fk_inventory_id (inventory_id),KEY idx_fk_customer_id (customer_id),KEY idx_fk_staff_id (staff_id),...);

EXPLAIN SELECT rental_id, staff_id FROM sakila.rentalWHERE rental_date = ‘2005-05-25’ AND inventory_id IN(1,2) ORDER BY customer_id;

Page 46: СУБД осень 2012 лекция 7

Нормализация

• Нормализованные таблицы обычно обновляются быстрее, чем ненормализованные.

• Когда данные хорошо нормализованы, они либо редко дублируются, либо не дублируются совсем. Так что изменять приходится меньше данных.

• Нормализованные таблицы обычно меньше по размеру, поэтому лучше помещаются в памяти и их производительность выше.

• Из-за отсутствия избыточных данных реже возникает необходимость в запросах с фразами DISTINCT или GROUP BY для извлечения списков значений.

Page 47: СУБД осень 2012 лекция 7

Денормализация

• Все данные находятся в одной и той же таблице, что позволяет избежать соединений.

• Более эффективные стратегии индексирования

SELECT message_text, user_nameFROM message

INNER JOIN user ON message.user_id=user.idWHERE user.account_type=’premium’ORDER BY message.published DESC LIMIT 10;

SELECT message_text,user_nameFROM user_messagesWHERE account_type=’premium’ORDER BY published DESCLIMIT 10;

Page 48: СУБД осень 2012 лекция 7

ДенормализацияТаблицы счетчиков

CREATE TABLE hit_counter (cnt int unsigned not null

) ENGINE=InnoDB;

UPDATE hit_counter SET cnt = cnt + 1;

Page 49: СУБД осень 2012 лекция 7

ДенормализацияТаблицы счетчиков

CREATE TABLE hit_counter (slot tinyint unsigned not null primary key,cnt int unsigned not null

) ENGINE=InnoDB;

UPDATE hit_counter SET cnt = cnt + 1 WHERE slot = RAND( ) * 100;

SELECT SUM(cnt) FROM hit_counter;

Page 50: СУБД осень 2012 лекция 7

ДенормализацияТаблицы счетчиков

CREATE TABLE daily_hit_counter (day date not null,slot tinyint unsigned not null,cnt int unsigned not null,primary key(day, slot)

) ENGINE=InnoDB;

INSERT INTO daily_hit_counter(day, slot, cnt) VALUES (CURRENT_DATE, RAND( ) * 100, 1) ON DUPLICATE KEY UPDATE cnt = cnt + 1;

Page 51: СУБД осень 2012 лекция 7

Спасибо за вниманиеПавел Щербинин

[email protected]