我在 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
user_id
、currency_id
和transaction_amount
都定义为 中的NOT NULL
列dbo.transactions
。但是,当我在 Management Studio 的对象资源管理器中查看视图定义时,它会将视图中的两个balance_amount
和标记transaction_count
为NULL
-able 列。
我看过几个讨论,这个是其中最相关的,这表明一些函数的改组可能有助于 SQL Server 识别视图列始终是NOT NULL
. 但是,在我的情况下,不可能进行这样的改组,因为在索引视图中不允许ISNULL()
聚合函数上的表达式(例如over the SUM()
) 。
有什么方法可以帮助 SQL Server 认识到这一点
balance_amount
并且transaction_count
可以NOT NULL
吗?如果不是,我是否应该担心这些列被错误地标识为
NULL
-able?我能想到的两个问题是:
- 映射到余额视图的任何应用程序对象都得到了不正确的余额定义。
- 在非常有限的情况下,查询优化器无法使用某些优化,因为它不能保证这两列是
NOT NULL
.
这些担忧中的任何一个都很重要吗?我还有其他需要注意的问题吗?
在我看来,SQL Server 有一个笼统的假设,即聚合可以产生 a
null
即使它操作的字段是not null
. 这在某些情况下显然是正确的:group by
在like的广义版本中也是如此cube
这个更简单的测试用例说明了任何聚合都被解释为可以为空的观点:
IMO 这是 SQL Server 的一个限制(尽管是一个小限制)——其他一些 RDBMS 允许对未强制执行的视图创建某些约束,这些约束只是为了给优化器提供线索而存在,尽管我认为“唯一性”更有可能有助于生成比“可空性”更好的查询计划
如果列的可空性很重要,可能与 ORM 一起使用,请考虑将索引视图包装在另一个简单地保证不可空性的视图中,使用
ISNULL
:我认为没有任何方法可以强制 SQL Server 将这些列识别为不可为空,即使它们显然不是。例如,您可以尝试更改
ISNULL
/COALESCE
围绕内部SUM()
表达式定义的顺序,但这无济于事。我也不相信你会错过任何优化 - 这些列当前没有索引,所以优化器不能选择不同的访问方法来确定所有
balance_amount
值 > 10000。那里可能是这样一种情况,如果您在其中一个列上创建非聚集索引,您可能会得到比不存在索引时更好的估计,但这与可空性无关。从性能的角度来看,我不会太担心这一点。我回去查看了我多年来创建的一堆索引视图,这些聚合列都是可以为空的。他们表现得很好。
再一次,就对象映射而言,我不会太担心它。由于应用程序无法更新索引视图,因此它认为
balance_amount
可以是null
. 它永远不会收到 anull
,也不能尝试写 anull
,所以<shrug>
。