4

我有如下查询:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE ISNULL(t1.DeleteFlag,'N') = 'N'

我有一个索引,我认为应该会导致该部分有一个索引搜索,= 'N'但我看到的是一个非常昂贵的索引扫描。索引是否有可能弄乱了索引的正确使用?DeleteFlag在只有几个可能值的列上创建索引(如will)是否有意义?

4

3 回答 3

9

是的,WHERE 子句中的任何函数调用都可能使索引无用。尝试重写它,以便可以使用索引:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE NOT t1.DeleteFlag = 'Y'

如果您期望从查询中获得的结果数远小于表中的总行数,则该索引是有意义的。

于 2009-12-22T22:24:14.963 回答
8

1) 使用 ISNULL 是否会将 Seek 变成 Scan?是的。将函数应用于列通常会使表达式不可 SARG(不可搜索)。为了将索引考虑用于 Seek 操作,引擎需要知道要寻找什么值,作为原始二进制值。一旦将函数应用于您要求搜索函数结果的列,它就必须在每一行上评估函数以查看结果是否恰好满足条件。

2)在选择性非常低(2-3 个值)的列上建立索引是否有意义?是的,但从不作为独立的索引表达式。索引临界点将使低选择性列上的独立索引只是浪费空间。但是当由更多的键组成时,像位和标志这样的选择性非常低的列作为索引中最左边的键非常有用。在您的情况下,鉴于已删除标志,作为聚集索引的第一个键是有意义的,因为预计每个查询都将指定“IsDeleted”条件。

我还要补充一点,您可能不应该在“已删除”标志上使用 NULL。

于 2009-12-22T22:40:37.083 回答
8

Mark Byers 的回答不起作用,这是由于 SQL Server 处理空值的一种非常微妙的方式。在 WHERE 表达式“t1.DeleteFlag = 'Y'”中,如果 t1.DeleteFlag 为 NULL,则表达式返回 NULL。因此,执行 NOT (NULL) 也会返回 NULL,这会导致 WHERE 条件失败。尝试做这个测试:

DECLARE @myvar VARCHAR(1)
SET @myvar = NULL

SELECT 'OK' WHERE ISNULL(@myvar, 'N') = 'N' -- Baseline statement. Returns OK
SELECT 'OK' WHERE NOT (@myvar = 'Y')        -- Equivalent to answer above. Fails
SELECT 'OK' WHERE @myvar = 'N' OR @myvar IS NULL -- This is another way to do it. Also returns OK

第二个 select 语句不返回任何行,因此不等同于基线语句,因此不起作用。第三条语句是编写此查询的另一种方式,一个是有效的,另一个是仍然确保可以使用字段上的索引。

所以,这里是这个问题的正确答案:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE (t1.DeleteFlag = 'N' OR t1.DeleteFlag IS NULL)

另一种可能会产生名义上更好的性能结果的替代方法是将 DeleteFlag 字段定义为“NOT NULL”并给它一个 DEFAULT ''(一个空字符串)。然后,可以简单地编写查询而不用担心 NULL:

SELECT t1.v3, t2.v2
FROM t1
INNER JOIN t2
ON t1.v1 = t2.v1
WHERE t1.DeleteFlag = 'N'
于 2012-12-29T00:45:32.893 回答