MySQL 查询优化器的提示(hint)

  1. HIGT_PRIORTY 与 LOW_PRIORITY
    这个提示信息告诉MySQL,当多个语句同时访问同一张表时,哪个语句执行优先级变高或者变低
    上述提示在select,insert,delete,update中使用,但需要注意的是。这两个提示只适用于表锁的存储引擎,千万不能在InnoDB或者其他细粒度锁机制和并发控制的引擎中使用。即使在MyISAM中使用也需要注意,因为有可能导致并发插入被禁止,可能导致性能降低
mysql> select high_priority * from t1;
+----+------+------+------+
| id | m1   | m2   | m3   |
+----+------+------+------+
|  1 | m1   | v1   | k1   |
|  2 | m1   | v2   | k2   |
|  3 | m1   | v3   | k3   |
|  4 | m2   | v22  | k22  |
|  5 | m2   | v23  | k23  |
|  6 | m3   | v33  | k33  |
|  7 | m3   | v34  | k34  |
|  8 | m3   | v34  | k34  |
|  9 | m3   | v35  | k34  |
| 10 | m4   | v45  | k45  |
+----+------+------+------+
10 rows in set (0.00 sec)

2.DELAYED
这个提示对INSERT和REPLACE有效。MySQL会将使用该提示的语句理解返回给客户端,并将插入到的行数据存入缓冲区,等表空闲时将数据写入。日志系统使用这样的提示会非常有效,或者其他需要写入大量数据但客户端不需要等待语句完成I/O的应用。这个用法有限制:并不是所有的存储引擎都支持这样的做法;并且该提示会导致函数LAST_INSERT_ID()无法正常工作

mysql> insert delayed into t1(m1,m2,m3) values('t2','t4','t5');
Query OK, 1 row affected, 1 warning (0.00 sec)

3.STRAIGHT_JOIN
默认情况在使用关联查询时,MySQL会将数据量小的表作为驱动表,查询数据。如下图(film为小表,actor数据量相对大):

mysql> explain select * from actor join film on film.f_id=actor.f_id \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
   partitions: NULL
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: actor
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 16.67
        Extra: Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

ERROR:
No query specified


mysql> explain select * from film join actor on film.f_id=actor.f_id \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
   partitions: NULL
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: actor
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 16.67
        Extra: Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

ERROR:
No query specified

可见,无论改变表顺序,MySQL都以film表为驱动表进行查询,如下图,使用straight_join(straight_join关键词左侧为驱动表),则可以改变执行顺序

mysql> explain select * from actor straight_join film on film.f_id=actor.f_id \G;
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: actor
  partitions: NULL
        type: ALL
possible_keys: NULL
         key: NULL
     key_len: NULL
         ref: NULL
        rows: 6
    filtered: 100.00
       Extra: NULL
*************************** 2. row ***************************
          id: 1
 select_type: SIMPLE
       table: film
  partitions: NULL
        type: ALL
possible_keys: PRIMARY
         key: NULL
     key_len: NULL
         ref: NULL
        rows: 2
    filtered: 50.00
       Extra: Using where; Using join buffer (Block Nested Loop)
2 rows in set, 1 warning (0.00 sec)

ERROR:
No query specified
  1. SQL_SMALL_RESULT和SQL_BIG_RESULT
    注意:该提示针对GROUP BY,DISTINCT或 DISTINCTROW的SELECT查询有效。SQL_SMALL_RESULT会告诉优化器结果集很小,可以存储在内存中的索引临时表中,以避免排序操作。如果是SQL_BIG_RESULT,则会告诉优化器,结果其可能很大,建议使用磁盘临时表做排序操作(TIP:MySQL做排序的算法是快排算法)
mysql> select SQL_SMALL_RESULT f_id from actor group by f_id;
+------+
| f_id |
+------+
|    1 |
|    2 |
+------+
  1. SQL_BUFFER_RESULT
    这个提示告诉优化器将查询的结果放到一个临时表,然后尽可能快的释放表锁。当没法使用客户端缓存时,使用服务器缓存通常很有效。当然也会消耗更多服务端内存(TIP:不适用于UNION查询)

看看官网对于SQL_SMALL_RESULT,SQL_BIG_RESULT和SQL_BUFFER_RESULT的解释

  • SQL_BIG_RESULT can be used with GROUP BY or DISTINCT to tell the
    optimizer that the result set has many rows. In this case, MySQL
    directly uses disk-based temporary tables if needed, and prefers
    sorting to using a temporary table with a key on the GROUP BY
    elements.
  • SQL_BUFFER_RESULT forces the result to be put into a temporary
    table. This helps MySQL free the table locks early and helps in
    cases where it takes a long time to send the result set to the
    client. This option can be used only for top-level SELECT statements,
    not for subqueries or following UNION.
  • SQL_SMALL_RESULT can be used with GROUP BY or DISTINCT to tell the
    optimizer that the result set is small. In this case, MySQL uses
    fast temporary tables to store the resulting table instead of using
    sorting. This should not normally be needed.

6.SQL_CACHE和SQL_NO_CACHE
建议配置query_cache_type为2(query_cache_type 0 代表不使用缓冲, 1 代表使用缓冲,2 代表根据需要使用。)
再根据需求再需要的SQL语句使用SQL_CACHE或SQL_NO_CACHE

mysql> select sql_cache * from film;
+------+--------------------------+---------------------+
| f_id | f_name                   | create_time         |
+------+--------------------------+---------------------+
|    1 | The Shawshank Redemption | 2021-04-07 02:14:15 |
|    2 | The Terminal             | 2021-04-07 02:15:38 |
+------+--------------------------+---------------------+
2 rows in set, 1 warning (0.00 sec)

不使用时:

mysql> select sql_no_cache * from film;
+------+--------------------------+---------------------+
| f_id | f_name                   | create_time         |
+------+--------------------------+---------------------+
|    1 | The Shawshank Redemption | 2021-04-07 02:14:15 |
|    2 | The Terminal             | 2021-04-07 02:15:38 |
+------+--------------------------+---------------------+
2 rows in set, 1 warning (0.00 sec)

7.SQL_CALC_FOUND_ROWS
一般配合FOUND_ROWS()函数使用。该提示不是优化提示,它会让MySQL返回的结果集包含更多的信息。如:查询中,它会除去LIMIT子句,查询要返回的结果总数。再通过FOUND_ROWS()函数取到总数值。
举例:

mysql> select * from actor;
+----------+------+----------------------+
| actor_id | f_id | actor_name           |
+----------+------+----------------------+
|        1 |    1 | Tim Robbins          |
|        2 |    1 | Morgan Freeman       |
|        3 |    1 | James Whitmore       |
|        4 |    2 | Tom Hanks            |
|        5 |    2 | Catherine Zeta-Jones |
|        6 |    2 | Stanley Tucci        |
+----------+------+----------------------+
6 rows in set (0.00 sec)

原数据

mysql> select sql_calc_found_rows * from actor limit 2;
+----------+------+----------------+
| actor_id | f_id | actor_name     |
+----------+------+----------------+
|        1 |    1 | Tim Robbins    |
|        2 |    1 | Morgan Freeman |
+----------+------+----------------+
2 rows in set (0.00 sec)

分页后数据

mysql> select found_rows();
+--------------+
| found_rows() |
+--------------+
|            6 |
+--------------+
1 row in set (0.00 sec)

使用FOUND_ROWS()获取了表actor的总数

注意:在高并发情况下,会存在对应数据对应不上的情况。另外,使用sql_calc_found_rows会是MySQL查询所有数据,使用过程中需要谨慎

  1. FOR UPDATE和LOCK_IN_SHARE_MODE
    这也不是真正的优化器提示。这两个提示主要控制SELECT语句的锁机制,且只对实现了行级锁的存储引擎有效。
    这两个提示会让某些优化无法正常使用,例如索引覆盖。InnoDB不能在不访问主键的情况下排他地锁定行,因为行的版本信息保存在主键中。

你可能感兴趣的:(MySQL 查询优化器的提示(hint))