Sql 甲骨文选择,带“;“在(多个值)”中;不使用索引
Oracle(12.1)不使用真正有利的索引。Sql 甲骨文选择,带“;“在(多个值)”中;不使用索引,sql,oracle,performance,optimization,Sql,Oracle,Performance,Optimization,Oracle(12.1)不使用真正有利的索引。 使用union all重写manuel查询有帮助,但确实很难看。 有什么想法吗 模式: 表“umsatz”,按“monat”的每个值进行分区(=年+月作为数字) 上的简单非唯一索引(monat,kundengruppe) 统计数据是可用的,并且是最新的 “monat”不是很有选择性(每个月有很多值),但“kundengruppe”列对其大多数值都有选择性。 “kundengruppe”具有混合柱状图,此处使用的具体值不会出现在表中(即,非常有选择
使用
union all
重写manuel查询有帮助,但确实很难看。有什么想法吗 模式:
- 表“umsatz”,按“monat”的每个值进行分区(=年+月作为数字)
- 上的简单非唯一索引(monat,kundengruppe)李>
- 统计数据是可用的,并且是最新的李>
- “monat”不是很有选择性(每个月有很多值),但“kundengruppe”列对其大多数值都有选择性。
“kundengruppe”具有混合柱状图,此处使用的具体值不会出现在表中(即,非常有选择性)-将其更改为很少出现的值不会改变任何东西。查询单个频繁出现的值会导致完整的表/分区扫描——在本例中这是可以的
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 14 | 3074 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 14 | | |
| 2 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 1 | 14 | 3074 | 00:00:01 |
| * 3 | INDEX RANGE SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 1 | | 3073 | 00:00:01 |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 3 - access("UB"."MONAT">=201701 AND "UB"."MONAT"<=201712)
* 3 - filter("UB"."KUNDENGRUPPE"=123 OR "UB"."KUNDENGRUPPE"=456 OR "UB"."KUNDENGRUPPE"=987)
.我可以用语义等价的UNION ALL手动重写中的多个值:
SELECT SUM(u.umsatz_euro)
FROM
(select * from umsatz u
where u.kundengruppe = 123
union all
select * from umsatz u
where u.kundengruppe = 456
union all
select * from umsatz u
where u.kundengruppe = 987
) u
WHERE u.monat BETWEEN 201701 AND 201712
执行计划三次使用索引,成本大大低于第一个计划(3000->14),Oracle甚至将“monat”谓词下推到每个选择中:
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 12 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
| 2 | VIEW | | 3 | 78 | 12 | 00:00:01 |
| 3 | UNION-ALL | | | | | |
| 4 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 1 | 14 | 4 | 00:00:01 |
| * 5 | INDEX RANGE SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 1 | | 3 | 00:00:01 |
| 6 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 1 | 14 | 4 | 00:00:01 |
| * 7 | INDEX RANGE SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 1 | | 3 | 00:00:01 |
| 8 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 1 | 14 | 4 | 00:00:01 |
| * 9 | INDEX RANGE SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 1 | | 3 | 00:00:01 |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 5 - access("UB"."MONAT">=201701 AND "UB"."KUNDENGRUPPE"=123 AND "UB"."MONAT"<=201712)
* 5 - filter("UB"."KUNDENGRUPPE"=123)
* 7 - access("UB"."MONAT">=201701 AND "UB"."KUNDENGRUPPE"=456 AND "UB"."MONAT"<=201712)
* 7 - filter("UB"."KUNDENGRUPPE"=456)
* 9 - access("UB"."MONAT">=201701 AND "UB"."KUNDENGRUPPE"=987 AND "UB"."MONAT"<=201712)
* 9 - filter("UB"."KUNDENGRUPPE"=987)
该计划使用(慢速)索引跳过扫描:
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 14 | 955 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 14 | | |
| 2 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 1769 | 24766 | 955 | 00:00:01 |
| * 3 | INDEX SKIP SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 1769 | | 36 | 00:00:01 |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 3 - access("UB"."MONAT">=201701 AND "UB"."KUNDENGRUPPE"=TO_NUMBER(:A) AND "UB"."MONAT"<=201712)
* 3 - filter("UB"."KUNDENGRUPPE"=TO_NUMBER(:A))
------------------------------------------------------------------------------------------------------------------------
|Id |操作|名称|行|字节|成本|时间|
------------------------------------------------------------------------------------------------------------------------
|0 | SELECT语句| | 1 | 14 | 955 | 00:00:01|
|1 |对骨料进行排序| | 1 | 14 | ||
|2 |按全局索引ROWID批处理的MAT|U视图访问| UMSATZ|U预算板| 1769 | 24766 | 955 | 00:00:01|
|*3 |索引跳过扫描| UMSATZ | U预算板| U GRP | U NUI | 1769 | 36 | 00:00:01|
------------------------------------------------------------------------------------------------------------------------
谓词信息(由操作id标识):
------------------------------------------
*3-访问(“UB”。“MONAT”>=201701和“UB”。“KUNDENGRUPPE”=TO_编号(:A)和“UB”。“MONAT”复合索引最终与所有索引类似,一个键后跟数据(rowid)
因此(monat,kundengruppe)上的索引在有序索引结构中的键在概念上类似于:
201701-123
201701-...
201701-...
201701-456
201701-...
201701-...
201701-987
201701-...
201701-...
201701-...
201701-...
201712-123
201712-...
201712-...
201712-456
201712-...
201712-...
201712-...
201712-987
201712-...
因此,当涉及到查询时,请记住这一点:
WHERE u.monat BETWEEN 201701 AND 201712 AND u.kundengruppe = 123
我有一个逻辑起点(201701-123)和逻辑终点(201702-123)
当我们向优化器演示以下内容时:
WHERE u.monat BETWEEN 201701 AND 201712 AND u.kundengruppe in (123,456,789)
这是一个更难提出的最佳索引使用策略
理想情况下,它可以在kundengruppe中对列表进行排序,并使用-key的索引访问,介于201701-[min list value]和201712-[max list value]之间,或者像手动重写一样将其分成3个单独的访问
但在这两种情况下,就访问成本而言,这都是一个艰难的命题,也就是说,它是使用的最佳选项吗,因为(根据我的索引键列表),可能散布在感兴趣的索引键之间的值的数量很难估计。类似地,在哪一点上,您会放弃将in列表拆分为各个部分的策略。如果第二个谓词是:
u.kundengruppe in (123,456,... [500 more values]...789)
在这种情况下,您可能不想将其拆分
很抱歉,我没有什么好的解决方案,但最终,您对优化器和(自动)查询转换的要求是有限的。我根据康纳的回答所引发的想法进行了一些测试。结果回答了我自己的问题
我将索引中的列顺序更改为(kundengruppe,monat)
,即选择性列排在第一位(“monat”只有大约30个不同的值,但被放在第一位,因为它是分区属性——在这种情况下,对于良好的访问是一个错误的想法)
现在,计划和成本看起来与预期一致:
SELECT SUM(u.umsatz_euro)
FROM umsatz u
WHERE u.monat BETWEEN 201701 AND 201712
AND u.kundengruppe IN (123,456,987)
-------------------------------------------------------------------------------------------------------------------------
|Id |操作|名称|行|字节|成本|时间|
-------------------------------------------------------------------------------------------------------------------------
|0 |选择语句| | 1 | 14 | 6 | 00:00:01|
|1 |对骨料进行排序| | 1 | 14 | ||
|2 | INLIST迭代器| | | | ||
|3 |按全局索引ROWID批处理的MAT|U视图访问| UMSATZ|U预算板| 1 | 14 | 6 | 00:00:01|
|*4 |索引范围扫描| UMSATZ | U预算板| U GRP | U NUI | 1 | 5 | 00:00:01|
-------------------------------------------------------------------------------------------------------------------------
谓词信息(由操作id标识):
------------------------------------------
*4-访问((“UB”。“KUNDENGRUPPE”=123或“UB”。“KUNDENGRUPPE”=456或“UB”。“KUNDENGRUPPE”=987)和“UB”。“MONAT”>=201701和“UB”。“MONAT”=201701和
“UB”。“MONAT”最近是否运行了表的聚集统计信息?使用索引提示的选项如何?统计信息是最新的(请参阅编辑的文本)。索引提示不会更改任何内容,可能是因为索引已被使用,但仅用于“MONAT”列。是否可以使用OEM?索引
WHERE u.monat BETWEEN 201701 AND 201712 AND u.kundengruppe in (123,456,789)
u.kundengruppe in (123,456,... [500 more values]...789)
SELECT SUM(u.umsatz_euro)
FROM umsatz u
WHERE u.monat BETWEEN 201701 AND 201712
AND u.kundengruppe IN (123,456,987)
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 14 | 6 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 14 | | |
| 2 | INLIST ITERATOR | | | | | |
| 3 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 1 | 14 | 6 | 00:00:01 |
| * 4 | INDEX RANGE SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 1 | | 5 | 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 4 - access(("UB"."KUNDENGRUPPE"=123 OR "UB"."KUNDENGRUPPE"=456 OR "UB"."KUNDENGRUPPE"=987) AND "UB"."MONAT">=201701 AND "UB"."MONAT"<=201712)
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 14 | 1518 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 14 | | |
| 2 | INLIST ITERATOR | | | | | |
| 3 | MAT_VIEW ACCESS BY GLOBAL INDEX ROWID BATCHED | UMSATZ_BUDGETBLATT | 2664 | 37296 | 1518 | 00:00:01 |
| * 4 | INDEX RANGE SCAN | UMSATZ_BUDGETBLATT_GRP_NUI | 2900 | | 12 | 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 4 - access(("UB"."KUNDENGRUPPE"=1899 OR "UB"."KUNDENGRUPPE"=2032 OR "UB"."KUNDENGRUPPE"=2160 OR "UB"."KUNDENGRUPPE"=2165 OR "UB"."KUNDENGRUPPE"=5048) AND "UB"."MONAT">=201701 AND
"UB"."MONAT"<=201712)
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 14 | 12494 | 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 14 | | |
| 2 | PARTITION RANGE ITERATOR | | 117769 | 1648766 | 12494 | 00:00:01 |
| * 3 | MAT_VIEW ACCESS FULL | UMSATZ_BUDGETBLATT | 117769 | 1648766 | 12494 | 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 3 - filter("UB"."KUNDENGRUPPE"=5047 AND "UB"."MONAT"<=201712)