SQL 执行计划的固定手段 --- Hint 方式(Hash Join)

本文介绍了如何通过Hint来控制SQL查询中的Hash Join操作,包括LEADING、SWAP_JOIN_INPUTS和NO_SWAP_JOIN_INPUTS等Hint的使用,以优化结合顺序和选择Build表与Probe表,避免笛卡尔积问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hash Join 中用到的 Hint

Hash Join 是不使用索引等价结合时,最有效的结合方式,所以,使用的机会非常之多。
Hash Join 是在内存中作出 Hash Table 用来存放结合数据。通常,会先访问数据量少的表,之后再访问数据量多的表,这样能保证性能。
先访问的表叫做 Build表,第二个访问的表叫做 Probe表。那么假如 3个以上的表进行 Hash Join 时,各表之间的结合顺序,以及那个表作为 Build表,那个表作为 Probe表,如何来控制呢。
下面我们介绍一下相关的 Hint 来进行有效的控制。

  • LEADING Hint (指定 Hash Join 顺序)
  • SWAP_JOIN_INPUTS Hint(指定 Build 表)
  • NO_SWAP_JOIN_INPUTS Hint(指定 Probe 表)
  • USE_HASH (指定使用 Hash Join)

下面用几个例子来做一下展示。

准备:

drop table t1 purge;
drop table t2 purge;
drop table t3 purge;
create table t1(c1 number, c2 number);
create table t2(c1 number, c2 number);
create table t3(c1 number, c2 number);
insert into t1 values (1,1);
insert into t2 values (1,2);
insert into t3 values (1,3);
commit;

Case 1:
结合顺序是 A->B(Build 表)->C

SQL> select /*+ leading(a b c) use_hash(b c) swap_join_inputs(b) */ * from t1 a, t2 b, t3 c where a.c1=b.c1 and a.c1=c.c1;

        C1         C2         C1         C2         C1         C2
---------- ---------- ---------- ---------- ---------- ----------
         1          1          1          2          1          3

Execution Plan
----------------------------------------------------------
Plan hash value: 1184213596

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     1 |    78 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN          |      |     1 |    78 |     9   (0)| 00:00:01 |
|*  2 |   HASH JOIN         |      |     1 |    52 |     6   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| T2   |     1 |    26 |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| T1   |     1 |    26 |     3   (0)| 00:00:01 |
|   5 |   TABLE ACCESS FULL | T3   |     1 |    26 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."C1"="C"."C1")
   2 - access("A"."C1"="B"."C1")

Case 2:
结合顺序是 A->B(Build表)->C(Build表)

SQL> select /*+ leading(a b c) swap_join_inputs(b) swap_join_inputs(c) */ * from t1 a, t2 b, t3 c where a.c1=b.c1 and a.c1=c.c1;

        C1         C2         C1         C2         C1         C2
---------- ---------- ---------- ---------- ---------- ----------
         1          1          1          2          1          3

Execution Plan
----------------------------------------------------------
Plan hash value: 1487401159

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     1 |    78 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN          |      |     1 |    78 |     9   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL | T3   |     1 |    26 |     3   (0)| 00:00:01 |
|*  3 |   HASH JOIN         |      |     1 |    52 |     6   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| T2   |     1 |    26 |     3   (0)| 00:00:01 |
|   5 |    TABLE ACCESS FULL| T1   |     1 |    26 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."C1"="C"."C1")
   3 - access("A"."C1"="B"."C1")

Case 3:
结合顺序是 A->C(Build表)->B

SQL> select /*+ leading(a c b) USE_HASH(c b) swap_join_inputs(c) */ * from t1 a, t2 b, t3 c where a.c1=b.c1 and a.c1=c.c1;

        C1         C2         C1         C2         C1         C2
---------- ---------- ---------- ---------- ---------- ----------
         1          1          1          2          1          3


Execution Plan
----------------------------------------------------------
Plan hash value: 2467348796

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     1 |    78 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN          |      |     1 |    78 |     9   (0)| 00:00:01 |
|*  2 |   HASH JOIN         |      |     1 |    52 |     6   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| T3   |     1 |    26 |     3   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL| T1   |     1 |    26 |     3   (0)| 00:00:01 |
|   5 |   TABLE ACCESS FULL | T2   |     1 |    26 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."C1"="B"."C1")
   2 - access("A"."C1"="C"."C1")

另外,以上面的例子来说,可以用 C->B->A 的顺序进行 Hash Join 吗。不可以哈,因为 B表和 C表之间没有结合键,这样会产生笛卡尔积。

SQL> select /*+ leading(c b a) USE_HASH(c b) */ * from t1 a, t2 b, t3 c where a.c1=b.c1 and a.c1=c.c1;

        C1         C2         C1         C2         C1         C2
---------- ---------- ---------- ---------- ---------- ----------
         1          1          1          2          1          3


Execution Plan
----------------------------------------------------------
Plan hash value: 2210115829

------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |     1 |    78 |     9   (0)| 00:00:01 |
|*  1 |  HASH JOIN            |      |     1 |    78 |     9   (0)| 00:00:01 |
|   2 |   MERGE JOIN CARTESIAN|      |     1 |    52 |     6   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL  | T3   |     1 |    26 |     3   (0)| 00:00:01 |
|   4 |    BUFFER SORT        |      |     1 |    26 |     3   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL | T2   |     1 |    26 |     3   (0)| 00:00:01 |
|   6 |   TABLE ACCESS FULL   | T1   |     1 |    26 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A"."C1"="B"."C1" AND "A"."C1"="C"."C1")
### GBD 数据库介绍 GBD 文件地理数据库是一种用于存储空间数据和属性数据的容器,支持复杂的数据结构以及丰富的地理处理功能。为了访问这种类型的地理数据库中的要素类和其他对象,通常依赖于特定驱动器的支持[^1]。 ### 使用方法 对于想要读取或写入 GDB 文件的操作而言,GDAL 提供了解析该种格式的能力。具体来说: - **安装必要的驱动**:确保已经安装了 FileGDB 或 OpenFileGDB 驱动来实现对 GDB 的读取能力。 - **加载并操作数据集**:通过 GDAL 库可以轻松打开 .gdb 文件夹形式存在的地理数据库,并对其进行查询、遍历等基本操作。 ```python from osgeo import ogr, gdal # 注册所有可用驱动 gdal.AllRegister() driver = ogr.GetDriverByName('OpenFileGDB') # 或者 'FileGDB' dataSource = driver.Open("path_to_your_gdb_file.gdb", 0) if dataSource is None: print("无法打开指定路径下的 GDB 文件") else: layerNames = [layer.GetName() for layer in dataSource] print(f"GDB 中包含图层: {', '.join(layerNames)}") ``` 上述代码展示了如何利用 Python 和 GDAL/ogr 打开一个 GDB 文件,并打印其中所含有的各个图层名称。 ### 应用场景 GBD 数据库广泛应用于 GIS( Geographic Information System 地理信息系统)领域内各种项目当中,比如城市规划、环境保护监测、资源管理等方面。由于其能够高效地管理和分析大规模的空间数据集合,在涉及到多维度时空数据分析的任务里表现尤为出色。 #### 特定案例展示 假设有一个名为 `city_planning` 的 GBD 文件地理数据库包含了多个关于某座城市的基础设施建设情况的相关信息表单(如道路网路分布、公共设施位置)。借助 GDAL 工具包提供的接口函数,开发者们便可以在不改变原有数据格式的前提下完成对该组数据的各种定制化需求处理工作,例如提取某些特定区域内的兴趣点列表或将不同来源的地图资料融合在一起形成新的专题地图产品。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值