我有一个相当简单的视图,正在尝试索引。
CREATE OR ALTER VIEW [schema].[IndexedView]
WITH SCHEMABINDING AS
SELECT
SUM(ISNULL([Quantity], 0)) as [Quantity],
[Address],
[Asset],
[schema].GetThirdAddressPart([Address]) AS [PortfolioId],
COUNT_BIG(*) AS [Count]
FROM
[schema].[table]
WHERE (
[Address] LIKE ('%:thing')
OR [Address] LIKE ('%:thing2')
OR [Address] LIKE ('%:thing3')
)
GROUP BY [Address], [Asset], [schema].GetThirdAddressPart([Address])
索引为
CREATE UNIQUE CLUSTERED INDEX [IDX_Index] ON [schema].[IndexedView]
(
[Asset] ASC,
[Address] ASC
)
函数 ( GetThirdAddressPart
) 的工作原理如下
CREATE FUNCTION [schema].[GetThirdAddressPart] (@inputString varchar(30))
RETURNS varchar(30) WITH SCHEMABINDING
AS
BEGIN
DECLARE @firstColonPos INT = CHARINDEX(':', @inputString);
DECLARE @secondColonPos INT = CHARINDEX(':', @inputString, @firstColonPos + 1);
DECLARE @thirdColonPos INT = CHARINDEX(':', @inputString, @secondColonPos + 1);
RETURN SUBSTRING(
@inputString,
@secondColonPos + 1,
CASE
WHEN @thirdColonPos = 0 THEN LEN(@inputString)
ELSE @thirdColonPos - @secondColonPos - 1
END
);
针对上述函数运行以下命令似乎支持该函数应该可以正常工作
SELECT ObjectPropertyEx(Object_Id('schema.GetThirdAddressPart'), N'IsDeterministic') AS deterministic,
ObjectPropertyEx(Object_Id('schema.GetThirdAddressPart'), N'IsPrecise') AS precise,
ObjectPropertyEx(Object_Id('schema.GetThirdAddressPart'), N'IsSystemVerified') AS verified,
ObjectPropertyEx(Object_Id('schema.GetThirdAddressPart'), N'UserDataAccess') AS UserDataAccess,
ObjectPropertyEx(Object_Id('schema.GetThirdAddressPart'), N'SystemDataAccess') AS SystemDataAccess;
给我...
我已经检查过,这满足使用 UDF 的要求。
如果我在通过 Docker ( ) 运行的 SQL Server 上本地运行此命令2022:latest
,则会收到以下错误
Msg 8668, Level 16, State 0, Line 34 Cannot create the clustered index 'IDX_Index' on view 'services-import.schema.IndexedView' because the select list of the view contains an expression on result of aggregate function or grouping column. Consider removing expression on result of aggregate function or grouping column from select list.
奇怪的是,如果我在 Azure SQL 数据库中运行它,索引就可以毫无问题地创建。两个数据库的兼容性级别相同。
本地问题在于 UDF,如果我将其注释掉,它将允许我对其进行索引。
- 通过 Docker 运行的 SQL Server 与通过 Azure SQL 数据库运行的行为有何不同?该文档似乎没有表明应该有。
- 我有什么办法可以解决这个问题吗?我意识到我可以将该函数作为计算列添加到原始表中,我只是想避免它。
SQL 版本:
Local:
Microsoft SQL Server 2022 (RTM-CU12) (KB5033663) - 16.0.4115.5 (X64) Mar 4 2024 08:56:10 Copyright (C) 2022 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 22.04.4 LTS) <X64>
Azure:
Microsoft SQL Azure (RTM) - 12.0.2000.8 Apr 19 2024 18:03:25 Copyright (C) 2022 Microsoft Corporation
好吧,错误消息在技术上是正确的:
该表达式是您的函数,它以Address作为参数,并出现在选择列表中。
地址是子句中的一列
GROUP BY
。因此,
...在 SQL Server 2022 CU12 上返回false 。它可能在 Azure SQL 数据库上返回true 。
代码库有很多共同点,但并不相同。
该结果代表了视图可索引性的最终决定。
消除问题
像这样的视图:
...是可索引的,尽管它并不直接适合您的情况。
解决方法
任何从字面上避免错误消息中的条件的更改都将起作用,例如通过更改分组列:
也许他们改进了 Azure SQL 数据库中的可索引性测试。
函数内联限制
请注意,由于当前的限制,您的函数不会内联到针对视图引用的基表执行的任何
INSERT
、UPDATE
、DELETE
或语句。由于物化视图是自动维护的,因此对于基表中更改的每一行,您的函数可能会被多次调用。MERGE
如果您担心这一点,请考虑使用稍微笨拙的表达式手动内联该函数:
胡乱猜测
我没有时间构建和测试重现,但我怀疑这是由于UDF 内联造成的。您可以尝试以这种方式重新创建您的函数,看看是否可以解决问题吗?
另请参阅KB4538581 - 修复:SQL Server 2022 和 2019 中的标量 UDF 内联问题