21.查询转换之-INLIST-FILTER

1.什么是IN-LIST-FILTER?

IN-LIST-FILTER是针对IN后面是子查询的一种处理方法,优化器会把IN后面的子查询所对应的结果集
当作过滤条件,并且走FILTER 类型的执行计划。
IN后面是子查询,意味着IN后面是变量的集合:走的是FILTER类型的执行计划,意味着Oracle并没有对 
IN后面的子查询做子查询展开。

走IN-LIST-FILTER类型的执行计划需要满足两个条件:
(1)目标SQL的IN后面是子查询而不是常量集合。
(2)Oracle未对目标SQL的IN后面的子查询做子查询展开。

2.IN-LIST-FILTER执行计划的案例

(1)
select t1.id,t1.name from test01 t1 where 
t1.id in(select /*+no_unnest*/t2.id from test01 t2 
where t2.name in ('348xsq348','349xsq349','350xsq350','351xsq351','352xsq352'));

Execution Plan
----------------------------------------------------------
Plan hash value: 1831486660

---------------------------------------------------------------------------------------
| Id  | Operation		     | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	     |	      |     1 |    21 |  3958K	(1)| 13:11:39 |
|*  1 |  FILTER 		     |	      |       |       | 	   |	      |
|   2 |   TABLE ACCESS FULL	     | TEST01 |  1000K|    20M|  1097	(1)| 00:00:14 |
|*  3 |   TABLE ACCESS BY INDEX ROWID| TEST01 |     1 |    21 |     4	(0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN	     | IDX_ID |     1 |       |     3	(0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "TEST01" "T2" WHERE
	      "T2"."ID"=:B1 AND ("T2"."NAME"='348xsq348' OR "T2"."NAME"='349xsq349' OR
	      "T2"."NAME"='350xsq350' OR "T2"."NAME"='351xsq351' OR
	      "T2"."NAME"='352xsq352')))
   3 - filter("T2"."NAME"='348xsq348' OR "T2"."NAME"='349xsq349' OR
	      "T2"."NAME"='350xsq350' OR "T2"."NAME"='351xsq351' OR "T2"."NAME"='352xsq352')
   4 - access("T2"."ID"=:B1)
Statistics
----------------------------------------------------------
	  1  recursive calls
	  0  db block gets
    2064660  consistent gets
	  0  physical reads
	  0  redo size
	719  bytes sent via SQL*Net to client
	519  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	  5  rows processed

(2)对比不加HINT,走的是NESTED LOOP类型的执行计划和BITMAP OR的执行计划。
做了子查询展开。
select t1.id,t1.name from test01 t1 where 
t1.id in(select t2.id from test01 t2 
where t2.name in ('348xsq348','349xsq349','350xsq350','351xsq351','352xsq352'));
Execution Plan
----------------------------------------------------------
Plan hash value: 2402577879
------------------------------------------------------------------------------------------------
| Id  | Operation			    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT		    |	       |     5 |   210 |    26	 (4)| 00:00:01 |
|   1 |  NESTED LOOPS			    |	       |     5 |   210 |    26	 (4)| 00:00:01 |
|   2 |   NESTED LOOPS			    |	       |     5 |   210 |    26	 (4)| 00:00:01 |
|   3 |    SORT UNIQUE			    |	       |     5 |   105 |    16	 (0)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID     | TEST01   |     5 |   105 |    16	 (0)| 00:00:01 |
|   5 |      BITMAP CONVERSION TO ROWIDS    |	       |       |       |	    |	       |
|   6 |       BITMAP OR 		    |	       |       |       |	    |	       |
|   7 |        BITMAP CONVERSION FROM ROWIDS|	       |       |       |	    |	       |
|*  8 | 	INDEX RANGE SCAN	    | IDX_NAME |       |       |     3	 (0)| 00:00:01 |
|   9 |        BITMAP CONVERSION FROM ROWIDS|	       |       |       |	    |	       |
|* 10 | 	INDEX RANGE SCAN	    | IDX_NAME |       |       |     3	 (0)| 00:00:01 |
|  11 |        BITMAP CONVERSION FROM ROWIDS|	       |       |       |	    |	       |
|* 12 | 	INDEX RANGE SCAN	    | IDX_NAME |       |       |     3	 (0)| 00:00:01 |
|  13 |        BITMAP CONVERSION FROM ROWIDS|	       |       |       |	    |	       |
|* 14 | 	INDEX RANGE SCAN	    | IDX_NAME |       |       |     3	 (0)| 00:00:01 |
|  15 |        BITMAP CONVERSION FROM ROWIDS|	       |       |       |	    |	       |
|* 16 | 	INDEX RANGE SCAN	    | IDX_NAME |       |       |     3	 (0)| 00:00:01 |
|* 17 |    INDEX RANGE SCAN		    | IDX_ID   |     1 |       |     2	 (0)| 00:00:01 |
|  18 |   TABLE ACCESS BY INDEX ROWID	    | TEST01   |     1 |    21 |     3	 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   8 - access("T2"."NAME"='348xsq348')
  10 - access("T2"."NAME"='349xsq349')
  12 - access("T2"."NAME"='350xsq350')
  14 - access("T2"."NAME"='351xsq351')
  16 - access("T2"."NAME"='352xsq352')
  17 - access("T1"."ID"="T2"."ID")
Statistics
----------------------------------------------------------
	  1  recursive calls
	  0  db block gets
	 31  consistent gets
	  0  physical reads
	  0  redo size
	719  bytes sent via SQL*Net to client
	519  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  1  sorts (memory)
	  0  sorts (disk)
	  5  rows processed

3.总结 
不做子查询展开的执行计划中出现FILTER;子查询最后一步被执行。
能做子查询展开的,优先执行子查询,并且该走索引的会走索引。

给下面代码添加注释: public List<ModelPropertyDTO> getpropertitySetsByGuids(List<String> guids, EngineModel engineModel, String language, String viewId, Boolean showEmpty) { Query query = new Query(); Criteria criteria = Criteria.where("modelId").is(engineModel.getId()); if (guids != null) { Criteria criteriaUuids = Criteria.where("uuid").in(guids); query.addCriteria(criteriaUuids); } if (!StringUtils.isEmpty(viewId)) { Criteria criteriaViewId = null; if (guids != null) { // 查具体构件时 criteriaViewId = Criteria.where("viewId").is(viewId); }else{ // 直接查整个分类时 criteriaViewId = Criteria.where("type.uuid").is(viewId); } query.addCriteria(criteriaViewId); /if (guids == null) { Criteria criteriaUuids = Criteria.where("uuid").is(viewId); query.addCriteria(criteriaUuids); }/ } query.addCriteria(criteria); query.fields().include("propertySets"); query.fields().include("modelId"); query.fields().include("uuid"); query.fields().include("type"); query.fields().include("systems"); query.fields().include("location"); query.fields().include("fillsVoids"); query.fields().include("extendObject"); query.fields().include("materialNames"); query.fields().include("voidsElements"); query.fields().include("entity"); query.fields().include("extend"); List<EngineObject> engineObjectList = mongotemplate.find(query, EngineObject.class); if (guids != null && guids.size() == 1) { //说明是单个查询构件信息 if (CollectionUtils.isNotEmpty(engineObjectList) && engineObjectList.size() == 2) { engineObjectList.forEach(engineObject -> { if (IfcEntityCategory.IFCBUILDING.getValue().equalsIgnoreCase(engineObject.getEntity())) { engineObjectRepository.delete(engineObject); } }); } } //query type: 模型所有几何构件 List<String> uuidsType = engineObjectList.stream().filter(engineObject -> engineObject.getType() != null).map(engineObject -> engineObject.getType().getUuid()).collect(Collectors.toList()); // Map<String, EngineObject> engineObjectMap = queryEnginObjectType(engineModel, uuidsType); List<ModelPropertyDTO> modelPropertyDTOList = getModelPropertyDTOS(language, engineObjectList, engineObjectMap, showEmpty); return modelPropertyDTOList; }
06-09
这是一个 Java 方法,接收四个参数:一个字符串列表 guids、一个 EngineModel 对象 engineModel、一个字符串 language、一个字符串 viewId 和一个布尔值 showEmpty。方法返回一个 ModelPropertyDTO 对象列表。 该方法的作用是根据给定的 guids,从 MongoDB 数据库中查询指定的 EngineObject 对象,并将这些对象转换为 ModelPropertyDTO 对象列表返回。 接下来逐行解释代码: ``` Query query = new Query(); // 创建 MongoDB 查询对象 Criteria criteria = Criteria.where("modelId").is(engineModel.getId()); // 创建查询条件,查询 modelId 等于 engineModel 的 id 的 EngineObject 对象 if (guids != null) { // 如果 guids 不为空 Criteria criteriaUuids = Criteria.where("uuid").in(guids); // 创建查询条件,查询 uuid 在 guids 中的 EngineObject 对象 query.addCriteria(criteriaUuids); // 将 uuid 查询条件添加到查询对象中 } if (!StringUtils.isEmpty(viewId)) { // 如果 viewId 不为空 Criteria criteriaViewId = null; if (guids != null) { // 如果 guids 不为空 criteriaViewId = Criteria.where("viewId").is(viewId); // 创建查询条件,查询 viewId 等于 viewId 的 EngineObject 对象 }else{ // 如果 guids 为空 criteriaViewId = Criteria.where("type.uuid").is(viewId); // 创建查询条件,查询 type.uuid 等于 viewId 的 EngineObject 对象 } query.addCriteria(criteriaViewId); // 将 viewId 查询条件添加到查询对象中 } query.addCriteria(criteria); // 将 modelId 查询条件添加到查询对象中 // 设置需要查询的字段 query.fields().include("propertySets"); query.fields().include("modelId"); query.fields().include("uuid"); query.fields().include("type"); query.fields().include("systems"); query.fields().include("location"); query.fields().include("fillsVoids"); query.fields().include("extendObject"); query.fields().include("materialNames"); query.fields().include("voidsElements"); query.fields().include("entity"); query.fields().include("extend"); // 从 MongoDB 数据库中查询符合条件的 EngineObject 对象 List<EngineObject> engineObjectList = mongotemplate.find(query, EngineObject.class); if (guids != null && guids.size() == 1) { // 如果 guids 不为空且只有一个元素 if (CollectionUtils.isNotEmpty(engineObjectList) && engineObjectList.size() == 2) { // 如果查询到的 EngineObject 对象不为空且数量为 2 engineObjectList.forEach(engineObject -> { // 遍历 EngineObject 对象列表 if (IfcEntityCategory.IFCBUILDING.getValue().equalsIgnoreCase(engineObject.getEntity())) { // 如果 EngineObject 对象的 entity 字段等于 IFCBUILDING engineObjectRepository.delete(engineObject); // 从数据库中删除该 EngineObject 对象 } }); } } // 查询类型为模型所有几何构件的 uuid 列表 List<String> uuidsType = engineObjectList.stream().filter(engineObject -> engineObject.getType() != null).map(engineObject -> engineObject.getType().getUuid()).collect(Collectors.toList()); // Map<String, EngineObject> engineObjectMap = queryEnginObjectType(engineModel, uuidsType); // 根据查询到的 EngineObject 对象列表生成 ModelPropertyDTO 对象列表 List<ModelPropertyDTO> modelPropertyDTOList = getModelPropertyDTOS(language, engineObjectList, engineObjectMap, showEmpty); // 返回 ModelPropertyDTO 对象列表 return modelPropertyDTOList; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值