sql >> Databáze >  >> RDS >> Sqlserver

Správné použití IsNULL a Coalesce

Toto bylo hašováno a znovu hašováno. Kromě tip, na který jsem upozornil v komentáři a výše uvedené odkazy a vysvětlení @xQbert, na požádání zde je vysvětlení COALESCE vs. ISNULL pomocí dílčího dotazu. Podívejme se na tyto dva dotazy, které jsou z hlediska výsledků totožné:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects), N'foo');

(Komentáře o použití TOP bez ORDER BY pro /dev/null/ děkuji.)

V případě COALESCE se logika ve skutečnosti rozšíří na něco takového:

SELECT CASE WHEN (SELECT TOP (1) ...) IS NULL
    THEN (SELECT TOP (1) ...)
    ELSE N'foo'
END

S ISNULL se to nestane. Zdá se, že existuje vnitřní optimalizace, která zajišťuje, že poddotaz je vyhodnocen pouze jednou. Nevím, jestli někdo mimo Microsoft přesně ví, jak tato optimalizace funguje, ale můžete to udělat, pokud porovnáte plány. Zde je plán verze COALESCE:

A zde je plán pro verzi ISNULL – všimněte si, o kolik je jednodušší (a že kontrola probíhá pouze jednou):

V případě COALESCE proběhne skenování dvakrát. To znamená, že poddotaz je vyhodnocen dvakrát, i když nepřinese žádné výsledky. Pokud přidáte klauzuli WHERE tak, že poddotaz poskytne 0 řádků, uvidíte podobnou disparitu – tvary plánu se mohou změnit, ale stále uvidíte dvojité hledání+vyhledání nebo skenování pro případ COALESCE. Zde je trochu jiný příklad:

SELECT COALESCE((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

SELECT ISNULL((SELECT TOP (1) name FROM sys.objects 
    WHERE name = N'no way this exists'), N'foo');

Plán pro verzi COALESCE tentokrát - opět vidíte celou větev, která představuje doslovně opakovaný poddotaz:

A opět mnohem jednodušší plán, který dělá zhruba polovinu práce pomocí ISNULL:

Můžete se také podívat na tuto otázku na dba.se pro další diskusi:

Můj návrh je tento (a mé důvody můžete vidět v tipu a výše uvedené otázce):důvěřujte, ale prověřujte. Vždy používám COALESCE (protože se jedná o standard ANSI, podporuje více než dva argumenty a nedělá tak podivné věci s prioritou datového typu) pokud Vím, že jako jeden z výrazů používám poddotaz (což si nepamatuji, že bych kdy dělal mimo teoretickou práci, jako je tato) nebo zažívám skutečný problém s výkonem a chci jen porovnat, zda má COALESCE vs. ISNULL nějaké podstatný rozdíl ve výkonu (který mimo případ poddotazu jsem ještě nenašel). Vzhledem k tomu, že téměř vždy používám COALESCE s argumenty podobných datových typů, jen zřídka musím provádět jiné testování, než se ohlížet na to, co jsem o tom řekl v minulosti (byl jsem také autorem článek o aspfaq, na který upozornil xQbert , před 7 lety).



  1. mysql komplikované sql

  2. Mapování sady výsledků JDBC na objekt

  3. Jak se mohu připojit k externí databázi z příkazu SQL nebo uložené procedury?

  4. Přidejte pole DATE a TIME, abyste získali pole DATETIME v MySQL