Як я можу допомогти SQL Server розпізнати стовпець індексованого перегляду, який НЕ може бути NULL?


9

У мене є такий індексований вигляд, визначений у 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. Однак, коли я переглядаю визначення перегляду в Object Explorer, він позначає як balance_amountі transaction_countяк NULLстовпці стовпців у поданні.

Я прийняв поглянути на кілька дискусій, це один є найбільш важливим з них, які припускають деяку перестановку функцій може допомогти SQL Server визнати , що стовпець вид завжди NOT NULL. У моєму випадку таке переміщення неможливо, оскільки вирази на сукупних функціях (наприклад, ISNULL()над SUM()) не допускаються в індексованих видах.

  1. Чи я можу допомогти SQL Server розпізнати це balance_amountта transaction_countє NOT NULLдієвим?

  2. Якщо ні, чи слід сумніватися, що ці стовпці помилково визначені як NULL-able?

    Дві проблеми, про які я міг би придумати:

    • Будь-які об’єкти програми, відображені на подання балансів, отримують неправильне визначення балансу.
    • У дуже обмежених випадках певні оптимізації недоступні Оптимізатору запитів, оскільки він не має гарантії з точки зору того, що ці два стовпці є NOT NULL.

    Чи є одна з цих проблем великою справою? Чи є якісь проблеми, які я маю пам’ятати?


Так, є проблеми, наприклад, ваш ORM створить зведені типи, що, в свою чергу, потребує додаткової обережності в коді при їх використанні, що марно (або навіть вводить в оману) у вашому випадку.
Марсель

Це також виявляється проблемою в рекурсивному cte при повторному повторенні в ненульовому полі (без сукупності), хоча IsNull (..., 0) в кінці може вилікувати.
crokusek

Відповіді:


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

І це справедливо і в узагальнених версіях group byподібногоcube

Цей простіший тестовий випадок ілюструє те, що будь-який агрегат трактується як нульовий:

CREATE VIEW dbo.balances
with schemabinding
AS
SELECT
      user_id
    , sum(1)   AS balance_amount
FROM dbo.transactions
GROUP BY
      user_id
;
GO

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;

Інформація про провідник SSMS


5

Я не думаю, що жодним чином ви можете змусити SQL Server розпізнавати ці стовпці як нерегульовані, хоча вони явно не є. Ви можете спробувати змінити порядок, як ви визначаєте ISNULL/ COALESCEнавколо виразу всередині SUM() , наприклад, але це не допоможе.

Я також не вірю, що є якісь оптимізації, які ви пропустите - ці стовпці наразі не індексуються, тому це не так, як оптимізатор може вибрати інший метод доступу, щоб визначити, скажімо, всі balance_amountзначення> 10000. Там може виникнути ситуація, коли, якщо ви створите некластеризований індекс в одному з цих стовпців, ви можете отримати трохи кращі оцінки, ніж якщо індекс не існує, але це не має нічого спільного з зведенням нанівець.

Я б не надто хвилювався з цього приводу з точки зору виступу. Я повернувся назад і подивився на купу індексованих поглядів, які я створив за ці роки, і ці стовпчики агрегації - це нуль. Вони виходять просто чудово.

Що стосується відображення об'єктів, я знову не переживаю за це. Оскільки програма не може оновити індексований вигляд, не має значення, чи вважає вона це balance_amountможливим null. Він ніколи не отримає null, і він не може спробувати написати null, так <shrug>.



@Aaron, щодо об’єктування об’єктів: я вважаю, що варто переглянути, оскільки картограф, ймовірно, генерує марні / оманливі об'єкти з нульовими типами, які ніколи не будуть реально використовуватися як такі.
Марсель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.