我有一个包含10列的表Employee。在我的查询where子句中我使用column1和column2。如果我在两列上创建索引 即column1和column2。是否有可能利用两个指数?
可以有两种方法: -
方法1:首先使用where子句索引,然后使用第二个where 第一个子句的子句结果返回进一步过滤而没有 使用第二个索引
方法2:对于首先使用where子句索引,获取行ID。对于 使用第二个where子句索引,获取行ID并进行交集 两个rowIds
索引如何在这里工作?
更新: -
如果MySQL或Oracle的策略不同,请将oracle视为DB
答案 0 :(得分:2)
对于Oracle,它取决于所使用的谓词的选择性。
在情况下,一个谓词具有高选择性而另一个谓词,将只使用一个索引,第二个谓词将在表上进行过滤。
这里是执行计划的一个例子
select * from tab where a = 250 and b = 2;
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 207 | 4 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TAB | 1 | 207 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_A | 1 | | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("B"=2)
2 - access("A"=250)
这里A
上的谓词只返回少数记录(1,但B上的谓词返回501行),只使用A列上的索引。
select
sum(case when a = 250 and b = 2 then 1 end) as cnt_ab,
sum(case when a = 250 then 1 end) as cnt_a,
sum(case when b = 2 then 1 end) as cnt_b
from tab2;
CNT_AB CNT_A CNT_B
---------- ---------- ----------
1 1 501
在情况下,两个索引都不是非常有选择性,但谓词组合是选择性的 Oracle可以使用转换为BITMAP索引或索引加入< / em>的。选择哪个访问路径取决于表统计信息和优化程序设置。在我的情况下,我获得了位图转换并使用INDEX_JOIN提示来获得另一个计划。 请注意,仅当查询仅返回索引中定义的列时,才可以进行索引连接。
select * from tab where a = 105 and b = 23;
谓词选择性
select
sum(case when a = 105 and b = 23 then 1 end) as cnt_ab,
sum(case when a = 105 then 1 end) as cnt_a,
sum(case when b = 23 then 1 end) as cnt_b
from tab;
CNT_AB CNT_A CNT_B
---------- ---------- ----------
200 21700 100000
转换为BITMAP
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 829 | 167K| 434 (1)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TAB | 829 | 167K| 434 (1)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 3 | BITMAP AND | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS | | | | | |
|* 5 | INDEX RANGE SCAN | IDX_A | 21552 | | 45 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS | | | | | |
|* 7 | INDEX RANGE SCAN | IDX_B | 21552 | | 190 (1)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("A"=105)
7 - access("B"=23)
索引加入
select /*+ INDEX_JOIN(a idx_a idx_b) */ a,b from tab where a = 105 and b = 23;
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 829 | 5803 | 235 (1)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 829 | 5803 | 235 (1)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN| IDX_A | 829 | 5803 | 45 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN| IDX_B | 829 | 5803 | 190 (1)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A"=105 AND "B"=23)
2 - access(ROWID=ROWID)
3 - access("A"=105)
4 - access("B"=23)
答案 1 :(得分:0)
(MySQL)
“ rowid”方法在MySQL中非常罕见。这可能是因为PRIMARY KEY
用于此操作,并且它直接进入行。
您要查询的是INDEX(a, b)
WHERE a=1 AND b=2 -- Good index
WHERE b=1 AND a=2 -- Good index (order does not matter _in the WHERE_)
WHERE a=1 AND b>2 -- Good index
WHERE b=1 AND a>2 -- Will ignore `b` in the index, but still use `a`
更多:http://mysql.rjweb.org/doc.php/index_cookbook_mysql
在其中可以使用row-id的地方:http://mysql.rjweb.org/doc.php/index1,但效率低于复合索引。