首页 > 数据库 >【GreatSQL优化器-01】const_table

【GreatSQL优化器-01】const_table

时间:2024-11-08 11:13:33浏览次数:1  
标签:tables 01 const GreatSQL t1 table c1 NULL

【GreatSQL优化器-01】const_table

file

一、const_table介绍

GreatSQL的优化器主要用JOIN类来进行处理SQL语句的,JOIN类有以下四个table数量相关的成员变量。其中const_tables是optimize最开始就检查并且标识的,因为这样可以把记录最少的表放在执行计划的第一步,在后面的执行计划里面这些const tables是不参与循环遍历和计算的,因此可以减少很多开销。

计数名称 说明 哪个函数进行累加
tables 该查询语句的所有表的数量,包含物化表和临时表 JOIN::get_best_combination()
primary_tables 该查询语句的主要表的数量,不包含物化表 JOIN::get_best_combination()
const_tables 该查询语句中只有0行或者1行的表数量 JOIN::extract_const_tables和JOIN::extract_func_dependent_tables
tmp_tables 该查询语句中临时表数量 JOIN::make_tmp_tables_info()

下面用一个简单的例子来说明 const_table 是什么。

greatsql> CREATE TABLE t1 (c1 int primary key, c2 varchar(32),date1 datetime);
greatsql> INSERT INTO t1 VALUES (1,'aaa','2021-03-25 16:44:00.123456'),(2,'bbb','2022-03-25 16:44:00.123456'),(3,'ccc','2023-03-25 16:44:00.123456');

# 这里看到以下的type类型是const,说明在优化器看来这是一张const table
greatsql> EXPLAIN SELECT * FROM t1 WHERE c1=1 AND c1<10;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t1    | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (3.60 sec)

# 这句sql语句最后被处理成以下的语句了,可以看到条件语句被提到前面当做列,最后的条件变为where true了。
greatsql> SHOW WARNINGS;
+-------+------+-------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                     |
+-------+------+-------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select '1' AS `c1`,'aaa' AS `c2`,'2021-03-25 16:44:00' AS `date1` from `db1`.`t1` where true |
+-------+------+-------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

二、const_table标识

const_table的寻找和标识在函数JOIN::extract_const_tables和JOIN::extract_func_dependent_tables进行处理,这两个函数的功能各有不同。用上面的例子来说明。

bool JOIN::make_join_plan() {
  if (!(query_block->active_options() & OPTION_NO_CONST_TABLES)) {
    // Detect tables that are const (0 or 1 row) and read their contents.
    //根据表的统计信息table->file->stats.records直接寻找该值为0或者1的表,并且表的cached_table_flags必须为HA_STATS_RECORDS_IS_EXACT,只有引擎是MyISAM和memory才有这个标志
    if (extract_const_tables()) return true;

    // Detect tables that are functionally dependent on const values.
    // 循环所有剩下的没有被标识的表,找出有索引或者有表依赖的表来标识
    if (extract_func_dependent_tables()) return true;
  }
}

bool JOIN::extract_func_dependent_tables() {
do {
  for (JOIN_TAB **pos = best_ref + const_tables; *pos; pos++) {
    一、遍历每张出现的表,寻找表里已经创建的索引。
    二、判断表有join条件的情况,本次不涉及
    三、判断表有表依赖的情况,本次不涉及
    四、检查表是否可以通过key读取或表仅使用 const ref。
    这里需要排除以下表:
    1. 全文搜索,或
    2. 嵌套外连接的一部分,或
    3. 半连接的一部分,或
    4. 具有大开销的外连接条件。
    5. 被 const 表优化的处理程序阻止。
    6. 将不会被使用,通常是因为它们是流式传输的而不是物化的(请参阅 Query_expression::can_materialize_directly_into_result())。
    7. 位于完整连接的两侧
    // 如果找到表有索引,这里用到的keyuse在之前JOIN::update_ref_and_keys()已经获取到。
    if (eq_part.is_prefix(table->key_info[key].user_defined_key_parts)) {
      // 该索引是唯一索引
      if (table->key_info[key].flags & HA_NOSAME) {
        if (const_ref == eq_part) {
          // 标识该表是const table
          mark_const_table(tab, start_keyuse);
          // 改变table的状态为const
          join_read_const_table(tab, positions + const_tables - 1);
        }
      }
    }
  }
} while ((const_table_map & found_ref) && ref_changed);

以下是实际使用的时候表扫描方式类型汇总,其中JT_CONST和JT_SYSTEM就是我们本章要说明的。JT_SYSTEM类型,这个需要跟JT_CONST区分开,JT_SYSTEM主要是扩展表而不是物理表,JT_SYSTEM表没有索引。JT_SYSTEM类型也会被计入const_tables,详情见下面。

join_type访问方法的类型 说明
JT_UNKNOWN 无效
JT_SYSTEM 表只有一行,比如select * from (select 1)
JT_CONST 表最多只有一行满足,比如WHERE table.pk = 3
JT_EQ_REF '=符号用在唯一索引
JT_REF '=符号用在非唯一索引
JT_ALL 全表扫描
JT_RANGE 范围扫描
JT_INDEX_SCAN 索引扫描
JT_FT Fulltext索引扫描
JT_REF_OR_NULL 包含null值,比如"WHERE col = ... OR col IS NULL
JT_INDEX_MERGE 一张表执行多次范围扫描最后合并结果
-- 下面的select 1表类型就是system而不是const。但是select 1这张表的数量也会计入const_tables
greatsql> EXPLAIN SELECT * FROM (SELECT 1);
+----+-------------+------------+------------+--------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table      | partitions | type   | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+------------+------------+--------+---------------+------+---------+------+------+----------+----------------+
|  1 | PRIMARY     | <derived2> | NULL       | system | NULL          | NULL | NULL    | NULL |    1 |   100.00 | NULL           |
|  2 | DERIVED     | NULL       | NULL       | NULL   | NULL          | NULL | NULL    | NULL | NULL |     NULL | No tables used |
+----+-------------+------------+------------+--------+---------------+------+---------+------+------+----------+----------------+
2 rows in set, 1 warning (12.33 sec)

三、实际例子说明

接下来看几个例子来说明上面的代码。

greatsql> CREATE TABLE t2 (c1 int, c3 varchar(32));
greatsql> CREATE index idx1 ON t2(c1);
greatsql> INSERT INTO t2 VALUES (1,'aaa'),(2,'bbb');

-- 非唯一索引不是const table
greatsql> EXPLAIN SELECT * FROM t2 WHERE c1=1 AND c1<10;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | idx1          | idx1 | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (3.84 sec)

-- 改变c1为primary key,看一下结果。
-- between条件也是唯一条件,因此是const table
-- 这里有个约束条件:BETWEEN的上下界条件值必须一样,才会被判定为const,否则是range
greatsql> EXPLAIN SELECT * FROM t1 WHERE c1 BETWEEN 1 AND 1 AND c1<10;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t1    | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

-- value in后面的值即使最小值和最大值相同也走的范围扫描,不被判定为const table
greatsql> EXPLAIN SELECT * FROM t1 WHERE c1 IN (1,1) AND c1<10;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

-- 下面的表只有一行,但是由于引擎不是MyISAM或者memory而不被判定为const table
greatsql> CREATE TABLE t3 AS SELECT 1 AS c1;
greatsql> EXPLAIN SELECT * FROM t3 WHERE c1=1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t3    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (1.91 sec)

-- 下面的表只有一行,由于引擎是MEMORY而被判定为const table
greatsql> CREATE TABLE t5 engine=memory AS SELECT 1 AS c1;
greatsql> EXPLAIN SELECT * FROM t5 WHERE c1=1;
+----+-------------+-------+------------+--------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type   | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t5    | NULL       | system | NULL          | NULL | NULL    | NULL |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+--------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (2.70 sec)

-- 两张表进行join的时候,即使这里t1的顺序在后面,因为在优化器里面被判定为const table,所以顺序被提前到第一位。
greatsql> EXPLAIN SELECT t1.c1,t1.c2 FROM t2,t1 WHERE t1.c1=1 AND t1.c1<10;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | t2    | NULL       | index | NULL          | idx1    | 4       | NULL  |    1 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set, 1 warning (2.70 sec)

greatsql> EXPLAIN FORMAT=TREE SELECT t1.c1,t1.c2 FROM t2,t1 WHERE t1.c1=1 AND t1.c1<10;
+-----------------------------------------------------+
| EXPLAIN                                             |
+-----------------------------------------------------+
| -> Index scan on t2 using idx1  (cost=0.35 rows=1)  |
+-----------------------------------------------------+
1 row in set (40.27 sec)

-- 通过打印堆栈查看当前最佳的排列顺序,可以看到表t1确实被提到第一个了。
Thread 56 "connection" hit Breakpoint 16, JOIN::get_best_combination (this=0x7fff14c6d0f0)
    at /sql/sql_optimizer.cc:3663
3663          for (Table_ref *sj_nest : query_block->sj_nests) {
(gdb) p best_ref[0]->table_ref->table_name
$99 = 0x7fff14c5d660 "t1"
(gdb) p best_ref[1]->table_ref->table_name
$100 = 0x7fff14c5d538 "t2"

四、总结

从上面优化器最早的步骤我们认识了const table的定义和判定方法,可以发现实际运用中const table是可以提高查询速度的。这里面通过唯一索引来定位查找数据是最快的就是因为被判定为const table,在后面的实践里面发现 =(等值查询)、特殊情况下的 BETWEEN 的时候都可以被认为是const table,但是 IN 却不行,因此实际运用的时候尽量不要用IN条件,而多用等值条件特殊条件下的BETWEEN来查询,最好是只用等值条件


Enjoy GreatSQL

标签:tables,01,const,GreatSQL,t1,table,c1,NULL
From: https://www.cnblogs.com/greatsql/p/18534695

相关文章

  • 代码随想录算法训练营第二十天|leetcode235. 二叉搜索树的最近公共祖先、leetcode701.
    1leetcode235.二叉搜索树的最近公共祖先题目链接:235.二叉搜索树的最近公共祖先-力扣(LeetCode)文章链接:代码随想录视频链接:二叉搜索树找祖先就有点不一样了!|235.二叉搜索树的最近公共祖先_哔哩哔哩_bilibili思路:用之前一样的方法,哈哈哈哈哈,好处就是做出来了,但是我觉得需......
  • P5479 [BJOI2015] 隐身术 题解
    题目传送门前置知识后缀数组简介|字符串哈希|二分解法考虑分别计算出编辑距离恰好等于\(k_{0}\in[0,k]\)的答案。观察在编辑距离的存在下,长度差至多为\(k\)。考虑设\(f_{i,j}\)表示最大的\(x\)使得\(s_{1\simx}\)和\(t_{1\simx+j}\)可以在\(i\)次编......
  • L1-013 计算阶乘和
    目录一、问题描述二、问题分析 三、源码解答四、参考资料一、问题描述对于给定的正整数N,需要你计算S=1!+2!+3!+...+N!。1.输入格式输入在一行中给出一个不超过10的正整数N。2.输出格式在一行中输出S的值。3.输入样例34.输出样例95.限制条件代码长......
  • CS5366,typec转HDMI,4K60Hz多功能拓展坞方案,低成本替代GSV2201,AG9411方案
    集睿致远ASL新推出的CS5366芯片是一款Type-C转HDMI2Lean4K60的视频转换芯片通过USBType-C连接器将DPRX视频信号转换为HDMI/DVITX视频信号。DP信号转接只用2lane,另外2lane可以输出USB3.0/3.1信号,同时兼容PD3.0,并支持双向PD,相较于CS5266刷新率从30HZ上提升到60HZ,采样频率最......
  • 101_api_intro_metadata_collegeenrollmentplan
    历年高校招生计划数据API数据接口基础数据/高校招生,各高校历年招生计划数据,高校招生数据/历年计划。1.产品功能支持历年高校招生计划数据查询;包含各高校招生计划详细数据;多维度查询条件支持;毫秒级查询性能;全接口支持HTTPS(TLSv1.0/v1.1/v1.2/v1.3);全面兼容......
  • 洛谷题单指南-二叉堆与树状数组-P2827 [NOIP2016 提高组] 蚯蚓
    原题链接:https://www.luogu.com.cn/problem/P2827题意解读:初始n个数,每次取最大值x,根据u/v分成两部分:x*u/v,x-x*u/v,然后其余数都增加q,整个过程重复m次。输出有两类数据:第t,2t,3t...次取出的最大值;最后剩余的数第t,2t,3t...个,从大到小输出。解题思路:直观上,通过模拟法可以实......
  • Microsoft Office 2019 (office全家桶)for Mac/Windows电脑安装包
    MicrosoftOffice2019forMac(Office全家桶)是一款功能全面且强大的办公软件套件,专为Mac用户设计。Mac苹果电脑下载:Office2019(含激活秘钥)Windows电脑下载:Office2019(含批量许可)    以下是其主要特点和优势:一、界面设计采用了Mac系统的设......
  • #473. 编辑 & P5479 [BJOI2015] 隐身术
    模拟赛出到加强版了,一点不会所以记录下。枚举每个后缀。设\(f_{i,j}\)为操作\(i\)次,长度增加\(j\),即插入的次数减删除的次数,所能匹配到的最大位置。也就是\(A\)的前\(f_{i,j}\)位匹配\(B\)的前\(f_{i,j}+j\)位。考虑转移。假如已经操作完了,那显然有\(f_{i,j}\ge......
  • 干货分享3:0.01元的付费引流方式,还是挺牛逼的!
    在淘宝看到一个很牛逼的产品,它的牛逼不是产品牛逼,而是价格牛逼…卖的也是一份虚拟资料。就是一份关于各种骗术的资料整理,没想到吧,这玩意还有这么多人会下单购买,我想更多的原因还是在于好奇心和价格便宜。0.01元卖了5000多份,合算下来是50元,虽然赚的不多,但也给我们打开一种思......
  • COMET 射线管 MXR101
    COMETMXR101射线管主要用于非破坏性检查和安全检查,适用于多种工业和安全领域。COMETMXR101射线管由瑞士COMET公司开发和制造,主要用于汽车、航空管道和钢铁行业中的材料非破坏性检查,以及在机场和边境的货物和行李的固定和移动检查。COMET公司一直致力于改进和简化X射线技术,其......