Nic*_*mas 9 sql-server-2008 null constraint view
我在 SQL Server 2008 中定义了以下索引视图(您可以从 gist下载工作架构以进行测试):
CREATE VIEW dbo.balances
WITH SCHEMABINDING
AS
SELECT
user_id
, currency_id
, SUM(transaction_amount) AS balance_amount
, COUNT_BIG(*) AS transaction_count
FROM dbo.transactions
GROUP BY
user_id
, currency_id
;
GO
CREATE UNIQUE CLUSTERED INDEX UQ_balances_user_id_currency_id
ON dbo.balances (
user_id
, currency_id
);
GO
Run Code Online (Sandbox Code Playgroud)
user_id
、currency_id
和transaction_amount
都定义为 中的NOT NULL
列dbo.transactions
。但是,当我查看 Management Studio 的对象资源管理器中的视图定义时,它在视图中将balance_amount
和都标记transaction_count
为NULL
可列。
我查看了几个讨论,这是其中最相关的一个,建议对函数进行一些改组可能有助于 SQL Server 识别视图列始终为NOT NULL
. 但是,在我的情况下不可能进行这种改组,因为在索引视图中不允许使用聚合函数上的表达式(例如ISNULL()
在 上SUM()
)。
有什么方法可以帮助 SQL Server 识别balance_amount
并且transaction_count
可以NOT NULL
吗?
如果没有,我是否应该担心这些列被错误地识别为NULL
-able?
我能想到的两个问题是:
NOT NULL
.这些问题中的任何一个都是大问题吗?我还有其他需要注意的问题吗?
Jac*_*las 10
user_id
、currency_id
、 和transaction_amount
都被定义为NOT NULL
列dbo.transactions
在我看来,SQL Server 有一个笼统的假设,即null
即使它操作的字段是not null
. 在某些情况下这显然是正确的:
create table foo(bar integer not null);
select sum(bar) from foo
-- returns 1 row with `null` field
Run Code Online (Sandbox Code Playgroud)
并且在group by
like的广义版本中也是如此cube
这个更简单的测试用例说明了任何聚合都被解释为可以为空的观点:
CREATE VIEW dbo.balances
with schemabinding
AS
SELECT
user_id
, sum(1) AS balance_amount
FROM dbo.transactions
GROUP BY
user_id
;
GO
Run Code Online (Sandbox Code Playgroud)
IMO 这是 SQL Server 的一个限制(尽管是次要的)-其他一些 RDBMS 允许对未强制执行的视图创建某些约束,并且存在仅用于向优化器提供线索,尽管我认为“唯一性”更有可能有助于生成比“可空性”更好的查询计划
如果列的可空性很重要,也许是为了与 ORM 一起使用,请考虑将索引视图包装在另一个视图中,该视图使用以下方法简单地保证非可空性ISNULL
:
CREATE VIEW dbo.balancesORM
WITH SCHEMABINDING
AS
SELECT
B.[user_id],
B.currency_id,
balance_amount = ISNULL(B.balance_amount, 0),
transaction_count = ISNULL(B.transaction_count, 0)
FROM dbo.balances AS B;
Run Code Online (Sandbox Code Playgroud)
我认为没有任何方法可以强制 SQL Server 将这些列识别为不可为空,即使它们显然不是。例如,您可以尝试更改在内部表达式中定义ISNULL
/的顺序,但这无济于事。COALESCE
SUM()
我也不相信您会错过任何优化 - 这些列当前未编入索引,因此优化器不能选择不同的访问方法来确定所有balance_amount
值 > 10000。有可能是这样一种情况,如果您在这些列之一上创建非聚集索引,您可能会得到比没有索引时更好的估计值,但这与可空性无关。
从性能的角度来看,我不会太担心这一点。我回去查看了我多年来创建的一堆索引视图,这些聚合列都是可以为空的。他们表现得很好。
再一次,就对象映射而言,我不会太担心。由于应用程序无法更新索引视图,因此它认为balance_amount
可以是null
. 它永远不会收到 a null
,也不能尝试写 a null
,所以<shrug>
.