cергей Голубчик, monty program ab
TRANSCRIPT
Оптимизатор запросов в MariaDB 10.0 — теперь и без индексов!
Сергей Голубчик MariaDB
Об этом докладе
● Engine Independent Statistics
● Что это такое
● Зачем это нужно
● Как считается
● Где хранится
● Примеры, примеры, примеры
Статистика данных: как это было
● Оптимизатор спрашивает движок:
● «сколько примерно строк в таблице?»
● «сколько стоит просканировать всю таблицу?»
● «сколько стоит прочитать столько-то строк из такого-то индекса?»
● «сколько раз в среднем каждое значение встречается в таком-то
индексе?»
● «сколько значений в таком-то индексе попадает в диапазон от… и
до…?»
Пример: нестабильность
● DBT-3: сложные аналитические запросы
● Q7: Volume Shipping Query
– 6 InnoDB таблиц
– 7 разных планов
– 12 минут, 25 минут, часы (таймаут)
● Q8: National Market Share Query
– 8 InnoDB таблиц
– 4 разных плана
– от 7 минут до 1.2 часа
Пример: неправда MariaDB [test]> CREATE TABLE t1 (a INT, b INT, c INT, KEY(a,b)) ENGINE=MyISAM;
MariaDB [test]> INSERT t1 VALUES (RAND()*1e5,RAND()*1e5,RAND()*1e5);
... 400 000 rows ...
MariaDB [test]> SELECT COUNT(DISTINCT a) AS cardinality FROM t1;
+-------------+
| cardinality |
+-------------+
| 97794 |
+-------------+
MariaDB [test]> SELECT cardinality FROM information_schema.statistics
--> WHERE table_name='t1' AND column_name='a';
+-------------+
| cardinality |
+-------------+
| 98304 |
+-------------+
MariaDB [test]> ALTER TABLE t1 ENGINE=InnoDB;
MariaDB [test]> SELECT cardinality FROM information_schema.statistics
--> WHERE table_name='t1' AND column_name='a';
+-------------+
| cardinality |
+-------------+
| 196914 |
+-------------+
Независимая статистика
● стабильная
● точная
● одинаковая для всех движков
Как это сделано
● новые таблицы в mysql
● конфигурационные переменные
● расширенная команда ANALYZE TABLE
Таблицы
● mysql.table_stats
● mysql.index_stats
● mysql.column_stats
Переменные
● @@use_stat_tables
● never
● complementary
● preferably
● @@optimizer_use_condition_selectivity
● 1 … 5
Команда ANALYZE TABLE
● ANALYZE TABLE table_name
● ANALYZE TABLE table_name PERSISTENT FOR ALL
● ANALYZE TABLE table_name PERSISTENT FOR
COLUMNS (column1, column2, ...)
INDEXES (index1, index2, ...)
Что считается
● по таблицам
● количество строк
● по индексам
● обратная мощность
Что считается
● по столбцам
● минимальное и максимальное значения
● процент NULL-ов
● средняя длина значения
● обратная мощность
● распределение значений (гистограмма)
Пример
CREATE TABLE t1 (a INT, b INT);
INSERT t1 SELECT RAND()*1e5, RAND()*1e5;
. . . . . . . . . . -- 512 тысяч строк
CREATE TABLE t2 (c INT, d INT, KEY(c), KEY(d));
INSERT t2 SELECT FLOOR(RAND()*1e5/2)*2, FLOOR(RAND()*1e5/3)*3 FROM t1;
CREATE TABLE t3 (e INT, f INT, KEY(f));
INSERT t3 SELECT * FROM t2;
ANALYZE TABLE t3;
SET OPTIMIZER_USE_CONDITION_SELECTIVITY=1;
SELECT * FROM t1, t2, t3 WHERE t3.f=t1.a AND t2.c=t1.a AND t3.e<5;
--> 1075 rows in set (1 min 19.25 sec)
SET OPTIMIZER_USE_CONDITION_SELECTIVITY=3;
SELECT * FROM t1, t2, t3 WHERE t3.f=t1.a AND t2.c=t1.a AND t3.e<5;
--> 1075 rows in set (13.17 sec)
Пример
MariaDB [test]> \. employees.sql
MariaDB [employees]> ANALYZE TABLE departments, dept_emp, dept_manager,
-> employees, salaries, titles;
MariaDB [employees]> SET OPTIMIZER_USE_CONDITION_SELECTIVITY=1;
Query OK, 0 rows affected (0.01 sec)
MariaDB [employees]> SELECT * FROM departments JOIN dept_emp USING (dept_no)
-> JOIN employees USING (emp_no) JOIN titles USING (emp_no) WHERE title='Manager';
24 rows in set (15.13 sec)
MariaDB [employees]> SET OPTIMIZER_USE_CONDITION_SELECTIVITY=3;
Query OK, 0 rows affected (0.01 sec)
MariaDB [employees]> SELECT * FROM departments JOIN dept_emp USING (dept_no)
-> JOIN employees USING (emp_no) JOIN titles USING (emp_no) WHERE title='Manager';
24 rows in set (0.53 sec)
Пример MariaDB [employees]> EXPLAIN EXTENDED SELECT * FROM departments JOIN dept_emp USING
(dept_no)
-> JOIN employees USING (emp_no) JOIN titles USING (emp_no) WHERE title='Manager';
+------+-------------+--------+---------+-------+----------+-----------------------+
| id | table | type | key | rows | filtered | Extra |
+------+-------------+--------+---------+-------+----------+-----------------------+
| 1 | departments | ALL | NULL | 9 | 100.00 | |
| 1 | dept_emp | ref | dept_no | 36844 | 100.00 | |
| 1 | employees | eq_ref | PRIMARY | 1 | 100.00 | |
| 1 | titles | ref | PRIMARY | 1 | 100.00 | Using index condition |
+------+-------------+--------+---------+-------+----------+-----------------------+
MariaDB [employees]> SET OPTIMIZER_USE_CONDITION_SELECTIVITY=3;
MariaDB [employees]> EXPLAIN EXTENDED SELECT * FROM departments JOIN dept_emp USING
(dept_no)
-> JOIN employees USING (emp_no) JOIN titles USING (emp_no) WHERE title='Manager';
+------+-------------+--------+---------+--------+----------+--------------------------
-----
| id | table | type | key | rows | filtered | Extra
+------+-------------+--------+---------+--------+----------+--------------------------
-----
| 1 | titles | ALL | NULL | 443308 | 14.29 | Using where
| 1 | employees | eq_ref | PRIMARY | 1 | 100.00 |
| 1 | dept_emp | ref | PRIMARY | 1 | 100.00 |
| 1 | departments | ALL | NULL | 9 | 77.78 | Using where; Using join
Неравномерное распределение
● Таблица скачиваний какого-то продукта N
● Пусть, пользователи могут регистрироваться
– и, где-то 1% на самом деле это делает
1,000,000 rows
среднее количество строк на значение: 500,000 10 000
990 000
Registered
YES
NO
… WHERE Registered = 'YES' …
Гистограммы
● histogram_size=20 или любое число больше нуля
● optimizer_use_condition_selectivity=4 или 5
● histogram_type=single_prec_hb или double_prec_hb
Гистограммы равной высоты
Пример MariaDB [employees]> SET OPTIMIZER_USE_CONDITION_SELECTIVITY=3;
Query OK, 0 rows affected (0.00 sec)
MariaDB [employees]> SELECT * FROM employees JOIN salaries
-> USING (emp_no) JOIN titles USING (emp_no) WHERE salary > 100000;
166014 rows in set (18.79 sec)
MariaDB [employees]> SET OPTIMIZER_USE_CONDITION_SELECTIVITY=4;
Query OK, 0 rows affected (0.00 sec)
MariaDB [employees]> SELECT * FROM employees JOIN salaries
-> USING (emp_no) JOIN titles USING (emp_no) WHERE salary > 100000;
166014 rows in set (6.64 sec)
Пример MariaDB [employees]> EXPLAIN EXTENDED SELECT * FROM employees JOIN salaries
-> USING (emp_no) JOIN titles USING (emp_no) WHERE salary > 100000;
+------+-----------+--------+---------+--------+----------+-------------+
| id | table | type | key | rows | filtered | Extra |
+------+-----------+--------+---------+--------+----------+-------------+
| 1 | titles | ALL | NULL | 443308 | 100.00 | |
| 1 | employees | eq_ref | PRIMARY | 1 | 100.00 | |
| 1 | salaries | ref | PRIMARY | 9 | 48.68 | Using where |
+------+-----------+--------+---------+--------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)
MariaDB [employees]> SET OPTIMIZER_USE_CONDITION_SELECTIVITY=4;
Query OK, 0 rows affected (0.00 sec)
MariaDB [employees]> EXPLAIN EXTENDED SELECT * FROM employees JOIN salaries
-> USING (emp_no) JOIN titles USING (emp_no) WHERE salary > 100000;
+------+-----------+--------+---------+---------+----------+-------------+
| id | table | type | key | rows | filtered | Extra |
+------+-----------+--------+---------+---------+----------+-------------+
| 1 | salaries | ALL | NULL | 2844047 | 4.76 | Using where |
| 1 | employees | eq_ref | PRIMARY | 1 | 100.00 | |
| 1 | titles | ref | PRIMARY | 1 | 100.00 | |
+------+-----------+--------+---------+---------+----------+-------------+
3 rows in set, 1 warning (0.01 sec)
Планы
● Другие типы гистограмм (например, равной ширины)
● Гистограммы для индексов (из нескольких столбцов!)
● Учет корреляций между столбцами
Вопросы?
Спасибо за внимание!