In version MySQL 5.7.7 Oracle presented a new promising feature: optimizer hints. However it did not publish any documentation about the hints. The only note which I found in the user manual about the hints is:

  • It is now possible to provide hints to the optimizer by including /*+ ... */ comments following the SELECTINSERTREPLACEUPDATE, or DELETE keyword of SQL statements. Such statements can also be used with EXPLAIN. Examples:

    SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1
    FROM t3 WHERE f1 > 30 AND f1 < 33;
    SELECT /*+ BKA(t1, t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
    SELECT /*+ NO_ICP(t1) */ * FROM t1 WHERE ...;

There are also three worklogs: WL #3996, WL #8016 and WL #8017. But they describe the general concept and do not have much information about which optimizations can be used and how. More light on this provided by slide 59 from Øystein Grøvlen’s session at Percona Live. But that’s all: no “official” full list of possible optimizations, no use cases… nothing.

I tried to sort it out myself.

My first finding is the fact that slide #59 really lists six of seven possible index hints. Confirmation for this exists in one of two new files under sql directory of MySQL source tree, created for this new feature.

$cat sql/opt_hints.h
...
/**
Hint types, MAX_HINT_ENUM should be always last.
This enum should be synchronized with opt_hint_info
array(see opt_hints.cc).
*/
enum opt_hints_enum
{
BKA_HINT_ENUM= 0,
BNL_HINT_ENUM,
ICP_HINT_ENUM,
MRR_HINT_ENUM,
NO_RANGE_HINT_ENUM,
MAX_EXEC_TIME_HINT_ENUM,
QB_NAME_HINT_ENUM,
MAX_HINT_ENUM
};

Looking into file sql/opt_hints.cc we can find out what these optimizations give not much choice: either enable or disable.

$cat sql/opt_hints.cc
...
struct st_opt_hint_info opt_hint_info[]=
{
{"BKA", true, true},
{"BNL", true, true},
{"ICP", true, true},
{"MRR", true, true},
{"NO_RANGE_OPTIMIZATION", true, true},
{"MAX_EXECUTION_TIME", false, false},
{"QB_NAME", false, false},
{0, 0, 0}
};

A choice for the way to include hints into SQL statements: inside comments with sign “+”

/*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */

, – is compatible with style of optimizer hints which Oracle uses.

We actually had access to these hints before: they were accessible via variable optimizer_switch. At least such optimizations like BKABNLICPMRR. But with new syntax we cannot only modify this access globally or per session, but can turn on or off particular optimization for a single table and column in the query. I can demonstrate it on this quite artificial but always accessible example:

mysql> use mysql
Database changed
mysql> explain select * from user where host in ('%', '127.0.0.1');
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | user | NULL | range | PRIMARY | PRIMARY | 180 | NULL | 2 | 100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.01 sec)
mysql> explain select /*+ NO_RANGE_OPTIMIZATION(user PRIMARY) */ * from user where host in ('%', '127.0.0.1');
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | PRIMARY | NULL | NULL | NULL | 5 | 40.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

I used one more hint, which we could not turn on or off directly earlier: range optimization.

One more “intuitively” documented feature is the ability to turn on or off a particular optimization. This works only for BKABNLICP and MRR: you can specify NO_BKA(table[[, table]…]), NO_BNL(table[[, table]…]), NO_ICP(table indexes[[, table indexes]…]) and NO_MRR(table indexes[[, table indexes]…]) to avoid using these algorithms for particular table or index in the JOIN.

MAX_EXECUTION_TIME does not require any table or key name inside. Instead you need to specify maximum time in milliseconds which query should run:

mysql> select /*+ MAX_EXECUTION_TIME(1000) */  sleep(1) from user;
ERROR 3024 (HY000): Query execution was interrupted, max_statement_time exceeded
mysql> select /*+ MAX_EXECUTION_TIME(10000) */ sleep(1) from user;
+----------+
| sleep(1) |
+----------+
| 0 |
| 0 |
| 0 |
| 0 |
| 0 |
+----------+
5 rows in set (5.00 sec)

QB_NAME is more complicated. WL #8017 tells us this is custom context. But what is this? The answer is in the MySQL test suite! Tests for optimizer hints exist in file t/opt_hints.test For QB_NAME very first entry is query:

EXPLAIN SELECT /*+ NO_ICP(t3@qb1 f3_idx) */ f2 FROM
(SELECT /*+ QB_NAME(QB1) */ f2, f3, f1 FROM t3 WHERE f1 > 2 AND f3 = 'poiu') AS TD
WHERE TD.f1 > 2 AND TD.f3 = 'poiu';

So we can specify custom QB_NAME for any subquery and specify optimizer hint only for this context.

To conclude this quick overview I want to show a practical example of when query hints are really needed. Last week I worked on an issue where a customer upgraded from MySQL version 5.5 to 5.6 and found some of their queries started to work slower than before. I wrote an answer which could sound funny, but still remains correct: “One of the reasons for such behavior is optimizer  improvements. While they all are made for better performance, some queries – optimized for older versions – can start working slower than before.”

To demonstrate a public example of such a query I will use my favorite source of information: MySQL Community Bugs Database. In a search for Optimizer regression bugs that are still not fixed we can find bug #68919 demonstrating regression in case the MRR algorithm is used for queries with LIMIT. In run queries, shown in the bug report, we will see a huge difference:

mysql> SELECT * FROM t1 WHERE i1>=42 AND i2<=42 LIMIT 1;
+----+----+----+----+
| pk | i1 | i2 | i3 |
+----+----+----+----+
| 42 | 42 | 42 | 42 |
+----+----+----+----+
1 row in set (6.88 sec)
mysql> explain SELECT * FROM t1 WHERE i1>=42 AND i2<=42 LIMIT 1;
+----+-------------+-------+------------+-------+---------------+------+---------+------+---------+----------+----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------+---------+------+---------+----------+----------------------------------+
| 1 | SIMPLE | t1 | NULL | range | idx | idx | 4 | NULL | 9999958 | 33.33 | Using index condition; Using MRR |
+----+-------------+-------+------------+-------+---------------+------+---------+------+---------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT /*+ NO_MRR(t1) */ * FROM t1 WHERE i1>=42 AND i2<=42 LIMIT 1;
+----+----+----+----+
| pk | i1 | i2 | i3 |
+----+----+----+----+
| 42 | 42 | 42 | 42 |
+----+----+----+----+
1 row in set (0.00 sec)

With MRR query execution takes 6.88 seconds and 0 if MRR is not used! But the bug report itself suggests using

optimizer_switch="mrr=off";

as a workaround. And this will work perfectly well if you are OK to run

SET optimizer_switch="mrr=off";

every time you are running a query which will take advantage of having it OFF. With optimizer hints you can have one or another algorithm to be ON for particular table in the query and OFF for another one. I, again, took quite an artificial example, but it demonstrates the method:

mysql> explain select /*+ MRR(dept_emp) */ * from dept_emp where to_date in  (select /*+ NO_MRR(salaries)*/ to_date from salaries where salary >40000 and salary <45000) and emp_no >10100 and emp_no < 30200 and dept_no in ('d005', 'd006','d007');
+----+--------------+-------------+------------+--------+------------------------+------------+---------+----------------------------+---------+----------+-----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+--------+------------------------+------------+---------+----------------------------+---------+----------+-----------------------------------------------+
| 1 | SIMPLE | dept_emp | NULL | range | PRIMARY,emp_no,dept_no | dept_no | 8 | NULL | 10578 | 100.00 | Using index condition; Using where; Using MRR |
| 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_key> | <auto_key> | 3 | employees.dept_emp.to_date | 1 | 100.00 | NULL |
| 2 | MATERIALIZED | salaries | NULL | ALL | salary | NULL | NULL | NULL | 2838533 | 17.88 | Using where |
+----+--------------+-------------+------------+--------+------------------------+------------+---------+----------------------------+---------+----------+-----------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

The post Optimizer hints in MySQL 5.7.7 – The missed manual appeared first on MySQL Performance Blog.

optimizer hints的更多相关文章

  1. 19 Using Optimizer Hints

    19.1 Overview of Optimizer Hints A hint is an instruction to the optimizer. In a test or development ...

  2. MYSQL COST optimizer

    http://blog.chinaunix.net/uid-26896862-id-3326400.html https://www.slideshare.net/olavsa/mysql-optim ...

  3. rule-based optimizer cost-based optimizer

    SQL processing uses the following main components to execute a SQL query: The Parser checks both syn ...

  4. 使用Ado.net执行SP很慢,而用SSMS执行很快

    今天遇到一个问题,有用户反应,在site上打开报表,一直loading,出不来结果. 遇到这种问题,我立刻simulate用户使用Filter Condition,问题repro,看来不是偶然事件,通 ...

  5. Peeking into Apache Flink's Engine Room

    http://flink.apache.org/news/2015/03/13/peeking-into-Apache-Flinks-Engine-Room.html   Join Processin ...

  6. SET Statements for SQLServer

    SET SHOWPLAN_ALL { ON | OFF } It will not execute the TSQL statements. It cannot be specified inside ...

  7. DBMS_STATS.GATHER_TABLE_STATS

    由于Oracle的优化器是CBO,所以对象的统计数据对执行计划的生成至关重要! 作用:DBMS_STATS.GATHER_TABLE_STATS统计表,列,索引的统计信息(默认参数下是对表进行直方图信 ...

  8. SQL Server 锁详解

    锁是一种防止在某对象执行动作的一个进程与已在该对象上执行的其他进行相冲突的机制.也就是说,如果有其他人在操作某个对象,那么你旧不能在该对象上进行操作.你能否执行操作取决于其他用户正在进行的操作. 通过 ...

  9. 来,看看MySQL 5.6, 5.7, 8.0的新特性

    对于MySQL的历史,相信很多人早已耳熟能详,这里就不要赘述.下面仅从产品特性的角度梳理其发展过程中的里程碑事件. 1995年,MySQL 1.0发布,仅供内部使用. 1996年,MySQL 3.11 ...

随机推荐

  1. Day15 HTML补充、初识JavaScript

    一.上节回顾 上节回顾: HTML 头部信息:编码.title.style.link(导入css文件) 身体: 内联 块级 --->inline-block(既有内联效果又有块级效果) a标签: ...

  2. linux下安装MySQL5.6记录

    把之前装的mysql卸载了,准备重新用代码包装一遍,问了一下公司的DBA,他推荐给我mysql-5.6.16版本,说这个版本比较稳定. 按照网上的教程安装,结果就少文件,我还在找原因的时候,同事来找我 ...

  3. SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆

    http://www.cnblogs.com/kissdodog/archive/2013/06/12/3132380.html

  4. 算法-KMP模式匹配算法

    1朴素算法:逐个比较 2 主要是解决多余比较的麻烦,通过处理比较字符串是否含有重复的字符的问题.

  5. python string 文本常量和模版

        最近在看python标准库这本书,第一感觉非常厚,第二感觉,里面有很多原来不知道的东西,现在记下来跟大家分享一下.     string类是python中最常用的文本处理工具,在python的 ...

  6. iOS 多线程学习笔记 —— NSOperation

    本文复制.参考自文章:iOS多线程编程之NSOperation和NSOperationQueue的使用 ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://b ...

  7. leetcode shttps://oj.leetcode.com/problems/surrounded-regions/

    1.从外围搜索O,深度搜索出现了 Line 35: java.lang.StackOverflowError Last executed input: ["OOOOOOOOOOOOOOOOO ...

  8. vijosP1471 教主的游乐场

    vijosP1471 教主的游乐场 链接:https://vijos.org/p/1471 [思路] 递推. 首先找到最左边的可以一步跳到后方的L, 那么L之后的点有两种情况:要么a足以跳到后方步数为 ...

  9. Matlab编程-图形处理功能

    绘图功能最基本的命令行:plot(y). 二维图形: (1) >> y=rand(100,1); >> plot(y) y是随机的实向量,以生成y的索引为横坐标,y为纵坐标绘图 ...

  10. linux0.12 编译过程

    感谢这篇文章的作者:    http://www.cnblogs.com/strugglesometimes/p/4231359.html 编译是个很蛋疼的事情,本想把linux0.12在bochs上 ...