ToprowDB Dynamic Server 查询优化技术---子查询优化--01-1

ToprowDB Dynamic Server 查询优化技术


(三)ToprowDB Dynamic Server 查询优化技术之子查询

本篇是《ToprowDB Dynamic Server 查询优化技术》系列的第三篇,探讨ToprowDB逻辑查询优化技术中的子查询优化技术。

在第二篇里,探讨了视图优化,这一次探讨子查询优化,我们也许会有一些 “故地重游似曾相识”的感觉,感觉子查询和视图优化怎么那么相似?其实,这种感觉,是一种正确的良好的感觉,或者叫做直觉吧。视图和子查询确实相似,从长像看,放在SQL语句中,两者都导致了query产生了嵌套;从优化技术看,都是要消除嵌套、把子部分去除合并到父亲节点;所以,本质上,视图和子查询的优化方式是一样的,称之为“上拉/扁平化”优化。(提高效率,扁平化管理,一些歪想,神思千里…….托着下巴,想想扁平化后的好处……

1 什么样的子查询,可以被优化?

    什么样的子查询,可以被优化?

    标题有点大,不过不是标题党,前面我们说视图和子查询的优化相似,那么视图如果可以被优化,似乎子查询的优化就是有路可寻的,或者聪明的你一定会想到,SPJ类型的子查询,是可以被优化的,非SPJ类型的子查询,是不可以被优化的,是吧?

1.1 SPJ类型子查询

沿用上一篇视图优化中提供的示例,我们进行如下的子查询:

SELECT * FROM (SELECT * FROM t1,t2) AS v_SPJ, t3;

注意视图优化篇中提及的是:SELECT * FROM v_SPJ, t3;

 

然后在ToprowDB中得到的查询执行计划可能如下(取决于统计数据导致的代价估算模型的计算值):-

ToprowDB Dynamic Server 查询优化技术---子查询优化--01-1 - 那海蓝蓝 - 那海蓝蓝的博客
 


    这里的子查询,是SPJ类型的子查询,与SPJ类型的视图相似,被优化,即子查询被消除。

1.2 SPJ类型的子查询

    SPJ子查询,类似非SPJ类型的视图,如果子查询的语句中包含有如下子句,这样的子查询,称为非SPJ类型的子查询:

1 GROUP BY子句

2 DISTNICT子句

3 聚集函数

4 带有集合操作: UNION / UNION DISTINCT / UNION ALL

5 带有分析函数、connect byOUTER JOINPL/SQL function

 

同样用一个例子来说明:

执行:SELECT * FROM t3, (SELECT DISTINCT t1.b1, t2.b2 FROM t1, t2 GROUP BY t1.b1, t2.b2) AS v_NON_SPJ;

ToprowDB Dynamic Server 查询优化技术---子查询优化--01-1 - 那海蓝蓝 - 那海蓝蓝的博客
 


左侧执行计划中的t1t2,是原始SQL中的t2t1,这2个表作了连接操作,得到一个临时的结果集((Temp Table For View)),这说明子查询v_NON_SPJ没有解体,即子查询v_NON_SPJquery被单独执行了。换句话说,SPJ类型的子查询不能被优化。

 

前面2个例子,说明了子查询的优化,和视图优化,确实是相似的,遵循着一样的规律,都是要区分SPJ类型还是非SPJ类型,前者可以被优化而后者不能被优化。

2 所有的SPJ类型子查询/视图都可以被优化吗?

在第一节,我们提到SPJ类型的子查询/视图是可以被优化的,那么,一个问题是:所有的SPJ类型的子查询/视图都可以被优化吗?

如下将执行的SQL语句为:

S1SELECT * FROM t3 WHERE b3 IN (SELECT a1 FROM t1);

S2SELECT * FROM t3 WHERE b3 IN (SELECT id1 FROM t1);

S3SELECT * FROM t3 WHERE id3 IN (SELECT a1 FROM t1);

S4: SELECT * FROM t3 WHERE b3 IN (SELECT b1 FROM t1 WHERE a1=a3);

 

2.1 S1语句

SELECT * FROM t3 WHERE b3 IN (SELECT a1 FROM t1)  //非相关的子查询

可以得到如下的执行计划:

Estimated Cost: 4

Estimated # of Rows Returned: 1

 

  1) informix.t3: SEQUENTIAL SCAN

 

        Filters: informix.t3.b3 = ANY <subquery>  //此处表明IN子查询被转换为ANY,但依旧是子查询

 

    Subquery:

    ---------

    Estimated Cost: 2

    Estimated # of Rows Returned: 1

 

      1) informix.t1: SEQUENTIAL SCAN

 

Query statistics:

-----------------

 

  Table map :

  ----------------------------

  Internal name     Table name

  ----------------------------

  t1                t3

 

  type     table  rows_prod  est_rows  rows_scan  time       est_cost

  -------------------------------------------------------------------

  scan     t1     6          1         6          00:00.13   4

 

    从上面的执行计划可以看出,非相关子查询没有被优化,嵌套层次依然存在。

 

2.2 S2语句

SELECT * FROM t3 WHERE b3 IN (SELECT id1 FROM t1)  //非相关的子查询,子查询目标列为索引列id1

执行计划如下:

 

Estimated Cost: 4

Estimated # of Rows Returned: 1

 

  1) informix.t3: SEQUENTIAL SCAN

 

        Filters: informix.t3.b3 = ANY <subquery>  //此处表明IN子查询被转换为ANY,但依旧是子查询

 

    Subquery:

    ---------

    Estimated Cost: 2

    Estimated # of Rows Returned: 1

 

      1) informix.t1: SEQUENTIAL SCAN

 

Query statistics:

-----------------

 

  Table map :

  ----------------------------

  Internal name     Table name

  ----------------------------

  t1                t3

 

  type     table  rows_prod  est_rows  rows_scan  time       est_cost

  -------------------------------------------------------------------

  scan     t1     6          1         6          00:00.06   4

 

 

Subquery statistics:  //存在子查询

--------------------

 

  Table map :

  ----------------------------

  Internal name     Table name

  ----------------------------

  t1                t1

 

  type     table  rows_prod  est_rows  rows_scan  time       est_cost

  -------------------------------------------------------------------

  scan     t1     3          1         3          00:00.00   2

 

    从上面的执行计划可以看出,ToprowDB对于非相关子查询不支持优化,嵌套层次依然存在。

 

 

2.3 S3语句

SELECT * FROM t3 WHERE id3 IN (SELECT a1 FROM t1)  //非相关的子查询,子查询左操作符为索引列id1

执行计划如下:

 

Estimated Cost: 3

Estimated # of Rows Returned: 1

 

  1) informix.t3: INDEX PATH  //此处变为索引扫描

 

    (1) Index Name: informix. 104_12

        Index Keys: id3   (Serial, fragments: ALL)  //id3上存在索引,而子查询值固定,所以可以对t3表执行索引扫描

        Lower Index Filter: informix.t3.id3 = ANY <subquery>  //此处表明IN子查询被转换为ANY,但依旧是子查询

 

    Subquery:

    ---------

    Estimated Cost: 2

    Estimated # of Rows Returned: 1

 

Query statistics:

-----------------

 

  Table map :

  ----------------------------

  Internal name     Table name

  ----------------------------

  t1                t3

 

  type     table  rows_prod  est_rows  rows_scan  time       est_cost

  -------------------------------------------------------------------

  scan     t1     3          1         3          00:00.10   4

 

 

Subquery statistics:

--------------------

 

  Table map :

  ----------------------------

  Internal name     Table name

  ----------------------------

  t1                t1

 

  type     table  rows_prod  est_rows  rows_scan  time       est_cost

  -------------------------------------------------------------------

  scan     t1     3          1         3          00:00.00   2

 

  type     rows_sort  est_rows  rows_cons  time

  -------------------------------------------------

  sort     3          0         3          00:00.02 //在子查询上执行了一个排序操作

   

    从上面的执行计划可以看出,非相关子查询左操作符带有主键索引列没有被优化,嵌套层次依然存在。但是, ToprowDB在子查询上执行了一个排序操作。

 

从前面的3个例子,我们可以看出,ToprowDB不支持对部分SPJ类型的子查询进行优化。

3 深入探讨

3.1 主流数据库对于例1至例3的优化情况

我们以MySQL 5.6.27PostgreSQL 9.5为例,看看第二节所述的子查询的在MySQLPostgreSQL的支持情况。

 

3.1.1 MySQL

3.1.1.1 S1语句

SELECT * FROM t3 WHERE b3 IN (SELECT a1 FROM t1)  //非相关的子查询

可以得到如下的执行计划:

mysql> explain SELECT * FROM t3 WHERE b3 IN (SELECT a1 FROM t1);

+----+-------------+-------+-------+------+----------------------------------------------------+

| id | select_type | table | type  | key  | Extra               |

+----+-------------+-------+-------+------+----------------------------------------------------+

|  1 | SIMPLE      | t1    | index | a1   | Using index               |

|  1 | SIMPLE      | t3    | ALL   | NULL | Using where; Using join buffer (Block Nested Loop) |

+----+-------------+-------+-------+------+----------------------------------------------------+

2 rows in set (0.00 sec)

    从查询执行计划看,嵌套不存在(id列的值相同表明不存在嵌套层次),子查询被消除,即被优化。

 

3.1.1.2 S2语句

SELECT * FROM t3 WHERE b3 IN (SELECT id1 FROM t1)  //非相关的子查询,子查询目标列为索引列id1

执行计划如下:

mysql> EXPLAIN SELECT * FROM t3 WHERE b3 IN (SELECT id1 FROM t1);

+----+-------------+-------+-------+------+----------------------------------------------------+

| id | select_type | table | type  | key  | Extra                                              |

+----+-------------+-------+-------+------+----------------------------------------------------+

|  1 | SIMPLE      | t1    | index | a1   | Using index                                        |

|  1 | SIMPLE      | t3    | ALL   | NULL | Using where; Using join buffer (Block Nested Loop) |

+----+-------------+-------+-------+------+----------------------------------------------------+

    从查询执行计划看,嵌套不存在,子查询被消除,即被优化。

 

 

3.1.1.3 S3语句

SELECT * FROM t3 WHERE id3 IN (SELECT a1 FROM t1)  //非相关的子查询,子查询左操作符为索引列id1

执行计划如下:

mysql> explain SELECT * FROM t3 WHERE id3 IN (SELECT a1 FROM t1);

+----+-------------+-------+--------+---------+--------------------------+

| id | select_type | table | type   | key     | Extra                    |

+----+-------------+-------+--------+---------+--------------------------+

|  1 | SIMPLE      | t1    | index  | a1      | Using where; Using index |

|  1 | SIMPLE      | t3    | eq_ref | PRIMARY | NULL                     |

+----+-------------+-------+--------+---------+--------------------------+

    从查询执行计划看,嵌套不存在,子查询被消除,即被优化。

 

    从上面的执行计划可以看出,MySQL对于ToprowDB不支持的三种子查询,都进行了优化。

3.1.2 PostgreSQL

3.1.2.1 S1语句

SELECT * FROM t3 WHERE b3 IN (SELECT a1 FROM t1)  //非相关的子查询

可以得到如下的执行计划:

postgres=# explain SELECT * FROM t3 WHERE b3 IN (SELECT a1 FROM t1);

                            QUERY PLAN

------------------------------------------------------------------

 Hash Semi Join  (cost=55.90..103.00 rows=1020 width=12)

   Hash Cond: (t3.b3 = t1.a1)

   ->  Seq Scan on t3  (cost=0.00..30.40 rows=2040 width=12)

   ->  Hash  (cost=30.40..30.40 rows=2040 width=4)

         ->  Seq Scan on t1  (cost=0.00..30.40 rows=2040 width=4)

    从查询执行计划看,嵌套不存在,子查询被消除变为“Semi Join”,即被优化。

 

3.1.2.2 S2语句

SELECT * FROM t3 WHERE b3 IN (SELECT id1 FROM t1)  //非相关的子查询,子查询目标列为索引列id1

执行计划如下:

postgres=# EXPLAIN SELECT * FROM t3 WHERE b3 IN (SELECT id1 FROM t1);

                            QUERY PLAN

------------------------------------------------------------------

 Hash Semi Join  (cost=55.90..103.00 rows=1020 width=12)

   Hash Cond: (t3.b3 = t1.id1)

   ->  Seq Scan on t3  (cost=0.00..30.40 rows=2040 width=12)

   ->  Hash  (cost=30.40..30.40 rows=2040 width=4)

         ->  Seq Scan on t1  (cost=0.00..30.40 rows=2040 width=4)

    从查询执行计划看,嵌套不存在,子查询被消除变为“Semi Join”,即被优化。

 

 

3.1.2.3 S3语句

SELECT * FROM t3 WHERE id3 IN (SELECT a1 FROM t1)  //非相关的子查询,子查询左操作符为索引列id1

执行计划如下:

postgres=# explain SELECT * FROM t3 WHERE id3 IN (SELECT a1 FROM t1);

                            QUERY PLAN

------------------------------------------------------------------

 Hash Semi Join  (cost=55.90..114.35 rows=2040 width=12)

   Hash Cond: (t3.id3 = t1.a1)

   ->  Seq Scan on t3  (cost=0.00..30.40 rows=2040 width=12)

   ->  Hash  (cost=30.40..30.40 rows=2040 width=4)

         ->  Seq Scan on t1  (cost=0.00..30.40 rows=2040 width=4)

    从查询执行计划看,嵌套不存在,子查询被消除变为“Semi Join”,即被优化。

 

    从上面的执行计划可以看出,MySQLPostgreSQL对于ToprowDB不支持的三种子查询,都进行了优化。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值