当中间列可以是任何东西时,是不是使用 3 列 SQL 索引?
Posted
技术标签:
【中文标题】当中间列可以是任何东西时,是不是使用 3 列 SQL 索引?【英文标题】:Is a 3 column SQL index used when the middle column can be anything?当中间列可以是任何东西时,是否使用 3 列 SQL 索引? 【发布时间】:2017-11-22 13:59:53 【问题描述】:目前正在尝试证明某些东西,看看是否需要添加索引。
如果我在 A、B、C 列上有一个索引,并且我在 where 子句中创建了一个仅显式使用 A 和 C 的查询,我会从索引中受益吗?
在这种情况下,想象 where 子句是这样的:
A = 'Q' AND (B is not null OR B is null) AND C='G'
我在 Oracle 中使用 EXPLAIN PLAN 对此进行了调查,但它似乎没有使用索引。此外,根据我对如何创建和使用索引的理解,它不会受益,因为由于缺乏细节,索引无法利用 B 列。
目前在 MSSQL 或 ORACLE 中查看此内容。不确定一个优化是否与另一个不同。
感谢任何建议!谢谢!
【问题讨论】:
Oracle 可以使用跳过扫描算法来利用这样的索引。我不认为 SQL Server 已经实现了这一点。B IS NOT NULL OR B IS NULL
应该被任何称职的优化器简单地过滤为始终为真的表达式,因此它应该对查询完全没有影响。 (即使这样做了,它用来实现它的任何行为都不会比根本不过滤 B
时更有效。)我简单的经验测试表明 SQL Server 确实将这个子句简化为无。
此外,至少在 SQL Server 2017 中,A, B, C
上的索引将被使用 - 将对所有带有 A = 'Q'
的行进行过滤搜索,使用C = 'G'
作为过滤谓词。我还没有查看C
上的这个过滤器是否比线性扫描更有效(我对此表示怀疑),但是考虑了索引 ,如果它被覆盖它仍然会改进访问时间超过了在 A
上只有一个索引。
在这种情况下,仅在列 A 和 B 上设置索引是否与在 A、B 和 C 上设置索引一样有效?目前有一个关于 A 和 B 的索引。感谢您的回复。很有帮助。
Still SQL server only:如果索引在A,B
,并且您的查询在A,C
,它并不比只在A
上的索引好,因为聚集索引查找将仍然需要返回C
。是否会使用索引取决于优化器是否认为表扫描比索引查找 + 一系列聚集索引查找更快。然而,在所有情况下,理论考虑永远不会胜过实际测量,因此,如果您是因为确实需要了解生产系统而提出这个问题,请帮自己一个忙,始终使用实际数据和实际索引进行测量。
【参考方案1】:
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
SQL> create table t$ (a integer not null, b integer, c integer, d varchar2(100 char));
Table created
SQL> insert into t$ select rownum, rownum, rownum, lpad('0', '1', 100) from dual connect by level <= 1000000;
1000000 rows inserted
SQL> create index t$i on t$(a, b, c);
Index created
SQL> analyze table t$ estimate statistics;
Table analyzed
SQL> explain plan for select * from t$ where a = 128 and c = 128;
Explained
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3274478018
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 4 (0)
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| T$ | 1 | 13 | 4 (0)
|* 2 | INDEX RANGE SCAN | T$I | 1 | | 3 (0)
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"=128 AND "C"=128)
filter("C"=128)
15 rows selected
有什么问题吗?
【讨论】:
只是为了澄清,这表明即使只使用列 A 和 C 仍然使用 3 列索引?至少最初按 A 过滤,然后扫描 C?当一个乱码 B 条件被添加到这个时会发生什么? 在我的系统中是一样的。 Oracle 使用基于成本的优化器,因此生成的计划不是绝对稳定的,其他人可以执行此脚本并获得不同的结果。但这表明三列索引有机会在这种情况下使用。我猜这首先取决于 A 列的选择性。 我明白你在说什么。谢谢!这很有帮助!【参考方案2】:如果看索引的B+树结构,那么答案如下 索引的左侧,包括第一个不等式,将转到 Seek Predicate,其余在 queryplan 中的 Predicate 中。
例如阅读http://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys
【讨论】:
以上是关于当中间列可以是任何东西时,是不是使用 3 列 SQL 索引?的主要内容,如果未能解决你的问题,请参考以下文章
pandas基于shift偏移dataframe中时间列计算相邻两列的时间差如果shift参数为1则指定列向下移动1个位置,使用后向填充进行缺失值填充
pandas利用shift偏移dataframe中时间列计算相邻两列的时间差使用apply函数将时间差转化为时间差对应的秒数(seconds)
PL/SQ连接oracle,L 新建表的时候, virtual那一列是啥意思
我下载了 bootstrap 5 和 jquery 3.6,问题是当我嵌入它们时,下拉按钮不起作用我的代码中是不是缺少任何东西?