给定以下常量:
给定这些常量,SQL Server 是否总是为给定的查询生成相同的计划?
如果没有,是否还有其他考虑?是否还需要考虑不确定性因素?
作为一般规则,如果它们确实是确定性的,我是否应该使用 DETERMINISTIC 关键字声明所有存储过程?
在我看来,大多数存储过程都是确定性的。我认为唯一的非确定性过程是调用 RAND() 或 CURDATE() 等非确定性函数的过程是否正确?
无论如何,我问的原因是因为当我在 MySQL Workbench 中使用数据恢复功能时,我收到此错误:
ERROR 1418 (HY000) at line 1209: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
Run Code Online (Sandbox Code Playgroud)
简单地设置“log_bin_trust_function_creators=1”是更好的做法吗?请记住,我有 50 多个存储过程。
我有两个函数:fn_Without_Param和fn_With_Param
CREATE FUNCTION [dbo].[fn_Without_Param]
(
)
...
INNER JOIN .. ON .. AND SubmitDate = CONVERT( varchar(10), GETUTCDATE(), 101 )
Run Code Online (Sandbox Code Playgroud)
和
/*
I am requesting it so:
declare @SubmitDate datetime
set @SubmitDate = CONVERT( varchar(10), GETUTCDATE(), 101 )
select * from [dbo].[fn_With_Param] (@SubmitDate)
*/
CREATE FUNCTION [dbo].[fn_With_Param]
(
@SubmitDate datetime
)
...
INNER JOIN .. ON .. AND SubmitDate = @SubmitDate
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我有不确定性 (?) 函数(因为 GETUTCDATE)并且我用相同的输入参数调用了第二个函数(CONVERT(varchar(10), GETUTCDATE(), 101 ) - 今天没有小时,分钟,秒,毫秒)。我的函数是不确定的吗?如何检测这一点,也许 sql server 有一些公共标记。为什么第二个函数更慢?
这是我尝试运行的查询类型:
WITH CTE_Ordered AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY PartitionField ORDER BY DateField) AS PartitionRowId
FROM SourceTable
),
CTE_Top1_PerPartition AS
(
SELECT *
FROM CTE_Ordered
WHERE PartitionRowId = 1
),
CTE_Calculations AS
(
SELECT AVG(NumberField1) AS NumberField1_Avg, StdDev.StdDev AS NumberField1_StdDev
FROM CTE_Top1_PerPartition
CROSS JOIN
(
SELECT STDEV(NumberField1) AS StdDev
FROM CTE_Top1_PerPartition
) AS StdDev
GROUP BY StdDev.StdDev
)
-- Final Select
SELECT *
FROM CTE_Calculations
Run Code Online (Sandbox Code Playgroud)
每次运行最终选择时,即使 SourceTable 是孤立的并且不会更改,我的 NumberField1_StdDev 值也会更改。
我注意到如果我首先将 CTE_Top1_PerPartition 选择到临时表中,然后从该临时表运行其余的查询,那么我每次都会得到相同的 NumberField1_StdDev 结果。
我猜这与结果在 CTE_Top1_PerPartition CTE …
我需要拆分一个逗号分隔的字符串,对其进行操作,然后将其连接回一个保留数据原始顺序的字符串(如果可能)。
例如,采用CREATE TABLE像这样的语句(作为字符串)的列定义列表'BrentOzarColumn INTEGER, PaulWhiteColumn DATETIME, ErikDarlingColumn VARCHAR(100)'。我想逗号分隔列表被划分到结果集,如使用SQL Server内置的功能STRING_SPLIT(),像这样:SELECT TRIM([Value]) AS CoolDataPeople FROM STRING_SPLIT('BrentOzarColumn INTEGER, PaulWhiteColumn DATETIME, ErikDarlingColumn VARCHAR(100)', ',')。
在不指定ORDER BY子句的情况下,这会重复产生(巧合?)以下结果,这些结果似乎按与字符串中相同的顺序排序:
一旦我得到了上面的结果集,我想对每一行应用一些额外的字符串操作(例如附加一些常量文本),然后将每一行连接回一个类似于STRING_AGG()(再见STUFF ... FOR XML PATH:)的函数,顺序与原始字符串。所以我的最终结果的一个例子可能是'BrentOzarColumn INTEGER SQLROX, PaulWhiteColumn DATETIME SQLROX, ErikDarlingColumn VARCHAR(100) SQLROX'.
最终我的问题是:函数的结果是否STRING_SPLIT()以确定性顺序返回?我知道没有ORDER BY子句,从 a Tableor等数据集中选择时不能保证排序View,但想知道函数是否有区别?
当我输入这个时,我有一种预感,答案是否定的,排序不是确定性的,因此我不能保证结果的顺序。此外,我打赌可能会为我在结果之上运行的每个函数添加额外的不确定性,尤其是当我将它们与STRING_AGG(). (不管答案如何,我感谢您的帮助,你们都是很酷的数据人员。;)
假设不使用 ORDER BY 子句,在实例化表并用连续插入填充表的 TABLE 值函数中,插入顺序是否具有确定性?
我需要查看发送给我们的给定数据集中使用的 Unicode 字符范围,以便弄清楚为什么 SSMS 中的查询结果中的某些空格(或者至少在眼睛看来是空格)没有被使用。在某些解析例程中,其行为类似于 char(32)。因此,我编写了一个快速而肮脏的函数,将相关列中的字符串值转换为一组可以查询的元组:
create function [foo].[AllChars]
(@in nvarchar(max))
returns @t TABLE (c nchar(1))
as
begin
declare @i int;
while len(@in)>0
begin
insert @t(c) values (left(@in,1));
set @in = substring(@in, 2, len(@in)-1)
end
return;
end
Run Code Online (Sandbox Code Playgroud)
可以这样称呼:
select X.c theChar, unicode(X.c) uValue
from myTable T
cross apply foo.AllChars(T.myCol) X
Run Code Online (Sandbox Code Playgroud)
并将为myTable中的每一行返回一组元组:
t 116
h 104
e 101
32
c 99
a 97
t 116
10 <= culprit
i 105
n 110
32 …Run Code Online (Sandbox Code Playgroud) sql-server determinism t-sql set-returning-functions non-deterministic
我正在调整 SQL Server 2012 中的查询,该查询由于DATENAME()在列上使用该函数检查数据是周末还是工作日时基数估计不正确而溢出到 tempdb 。由于使用该函数,查询是不可sargable的,并且错误估计了行数(估计1700,实际38000)。
where 子句很简单:
WHERE DATENAME(WEEKDAY, vqc.DateRecorded) NOT IN ('Saturday', 'Sunday')
Run Code Online (Sandbox Code Playgroud)
我希望使用持久计算列,然后对其进行索引:
ALTER TABLE <table_name> ADD IsWeekend AS DATENAME(WeekDay, DateRecorded) PERSISTED;
Run Code Online (Sandbox Code Playgroud)
但是得到错误:
无法保留表中的计算列“IsWeekend”,因为该列是不确定的。
根据BOL,大量 Date 函数无法持久化,因为它们是不确定的。
这是因为结果取决于服务器会话的 LANGUAGE 和 DATEFORMAT 设置。例如,表达式 CONVERT (datetime, '30 listopad 1996', 113) 的结果取决于 LANGUAGE 设置,因为字符串 '30 listopad 1996' 表示不同语言的不同月份。同样,在表达式 DATEADD(mm,3,'2000-12-01') 中,数据库引擎根据 DATEFORMAT 设置解释字符串 '2000-12-01'。
有一个有趣的方法来解决这个问题,该MONTH()函数使用CASE发布在Stack Overflow上的声明,但这对DATENAME由于SET DATEFIRST和LANGUAGE设置不起作用。
除了在我的查询中加入日历表然后从那里过滤周末之外,有没有办法确定日期是否是周末,以便它可以被持久化然后索引?
还是我想把情况复杂化?
determinism ×7
sql-server ×6
aggregate ×1
cte ×1
functions ×1
mysql ×1
order-by ×1
performance ×1
t-sql ×1