当中间列可以是任何东西时,是不是使用 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,问题是当我嵌入它们时,下拉按钮不起作用我的代码中是不是缺少任何东西?

求...判断一个点是不是在(不规则)四边形当中

在 SQL 中使用 group by 列 1、2、3、...、n 是不是有任何语法糖?