首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更改元数据更改查询输出问题

更改元数据更改查询输出问题
EN

Database Administration用户
提问于 2014-12-05 16:55:27
回答 2查看 197关注 0票数 4

最近偶然发现了以下问题:更改元数据更改查询输出。

这是如何得到它。

代码语言:javascript
复制
CREATE TABLE [dbo].[prod]
(
[ID] [tinyint] NOT NULL,
[values] [tinyint] NOT NULL
) 
GO

以下查询始终返回“这是结束”(总是引发错误)。另外,过滤器应该是某种随机生成器。

代码语言:javascript
复制
BEGIN TRY
SELECT [id] FROM 
        (
        SELECT [id] as [id]
        FROM dbo.prod
        WHERE ([id]=1/0)
        ) t1
WHERE
-- Random generator 1 always returns false
(FLOOR(RAND()*(1))=1)
-- Random generator 2 does not always return false
/*
SUBSTRING( cast(NEWID() as varchar(max)), 1, 1)
IN ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F')
*/
-- Random generator 3 does not always return false
/*
SUBSTRING(cast(cast( DATEPART(MILLISECOND,GETDATE()) as char(3)) as varchar(3)), 2, 1)
IN ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')
*/
END TRY
BEGIN CATCH
SELECT 'This is the end'
END CATCH;

现在添加主键约束。注:无数据更改。

代码语言:javascript
复制
ALTER TABLE dbo.prod
ADD CONSTRAINT PK_1 PRIMARY KEY NONCLUSTERED(id);

而现在同样的查询

代码语言:javascript
复制
BEGIN TRY
SELECT [id] FROM 
        (
        SELECT [id] as [id]
        FROM dbo.prod
        WHERE ([id]=1/0)
        ) t1
WHERE
(FLOOR(RAND()*(1))=1)
END TRY
BEGIN CATCH
SELECT 'This is the end'
END CATCH;

永远不要返回错误。

更改元数据可能会更改执行计划,这是可以理解的,但它更改查询的输出是意外的。这种行为正确吗?

EN

回答 2

Database Administration用户

回答已采纳

发布于 2014-12-06 07:19:39

这种行为正确吗?

这是故意的(故意的)行为;它是否“正确”更多地是一个意见问题。

要点是: Server不保证表达式的计算时间或数量。这种行为的存在是为了给查询优化器找到好的执行计划所需的自由。

因此,查询优化可能会改变查询的输出或运行时行为,如果依赖于表达式(或标量函数)的计算时间或数量。

在问题的示例中,运行时行为取决于查询优化器是否将每个表达式标识为运行时常量。执行引擎可以决定在查询执行开始之前计算(和缓存)运行时常量表达式。

如果优化器将表达式1/0标识为运行时常量,则显示计划输出的XML形式将显示它标记为ConstExprxxxx

像这样的运行时常量可以在查询执行开始之前计算一次,并缓存结果,如前所述。在这种情况下,在此预查询常量表达式计算期间,将返回除以零错误的结果。

将索引添加到表中碰巧是通过查询优化而进行的,这不会导致1/0被标记为运行时常量(下面没有ConstExprxxxx ):

在这种情况下,存在唯一性约束意味着优化器决定缓存表达式的结果没有好处,而表达式只能计算一次。启动筛选器意味着不计算错误表达式。

在所有情况下,这些表达式评估行为都不是由ConstExpr标签的存在来记录或完全确定的。答案不是编写取决于执行引擎对表达式的计算时间或数量的代码。

票数 5
EN

Database Administration用户

发布于 2014-12-05 19:14:00

有意思的。

这似乎是由于添加了唯一约束,该约束在ID上添加了一个索引,从而导致优化器使用索引查找而不是表扫描。

不幸的是,我不知道为什么索引index似乎不抛出零错误的除法,因为它显示了index谓词中的除法。

代码语言:javascript
复制
DECLARE @X TABLE 
(
ID Int IDENTITY(1,1) NOT Null,
    Value Int NOT Null
)

DECLARE @Y TABLE 
(
    ID Int IDENTITY(1,1) NOT Null UNIQUE,
    Value Int NOT Null
)


SELECT  ID
FROM    @X
WHERE ID = 1/0
AND Rand() = -1

SELECT ID
FROM @Y
WHERE ID = 1/0
AND Rand() = -1

嗯更奇怪的是..。如果创建一个表并添加索引,但使用查询提示“强制”表扫描,则查询仍然成功:

代码语言:javascript
复制
CREATE TABLE #X
(
    ID Int IDENTITY(1,1) NOT Null,
    Value Int NOT Null
)

--  Select from table, this errors on divide by zero
SELECT  ID
FROM    #X
WHERE ID = 1/0
AND Rand() = -1

--  Add a unique constraint to the table
ALTER TABLE #X ADD CONSTRAINT TEMP_X_CONSTRAINT UNIQUE (ID)

--  Select from table, this is successful
SELECT  ID
FROM    #X
WHERE ID = 1/0
AND Rand() = -1

--  Select from table forcing table scan, this is successful
SELECT ID
FROM #X WITH (INDEX(0))
WHERE ID = 1/0
AND Rand() = -1

我认为Server可能在它的实际执行计划方面对我们撒谎。

票数 3
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/84460

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档