Wie teste ich, ob XML = '' in SQL Server?

7

Ich arbeite mit SQL Server 2005 und hatte eine Situation, in der viele Werte in einem Parameter übergeben werden können.

Basierend darauf: Bei der Übergabe mehrerer Werte für einen SQL-Parameter wird bei dieser Prozedur XML als Parameter verwendet.

Hier ist der Code der gespeicherten Prozedur:

CREATE PROCEDURE [DENORMV2].[udpProductBulletPointSelectByTier1NoteTypeCode] (  
    @Tier1 VARCHAR(10),  
    @LanguageID INT,  
    @SeasonItemID VARCHAR(5) = NULL,
    @ListNoteTypeCode XML,  
    @CacheDuration INT OUTPUT )  
    WITH EXECUTE AS 'webUserWithRW'  
AS

        SELECT  pbp.Tier1, pbp.LanguageId, pbp.NoteText, pbp.NoteTypeCode,  
                pbp.NoteGroup, pbp.SortOrder  
        FROM    dbo.ProductBulletPoint pbp  

        WHERE   Tier1 = @Tier1 
          AND   LanguageId = @LanguageID 
          AND   (      SeasonItemId = @SeasonItemID  
                  OR
                       @SeasonItemID is null
                )

          AND pbp.NoteTypeCode IN (

                 SELECT  NoteTypeCode=BulletPoint.NoteTypeCode.value('./text()[1]', 'varchar(50)')
                   FROM  @ListNoteTypeCode.nodes('/BulletPoint/NoteTypeCode') AS BulletPoint ( NoteTypeCode )

          )

SELECT  @CacheDuration = Duration  
FROM    dbo.CacheDuration  
WHERE   [Key] = 'Product'
GO

Weitere Informationen zu diesem Verfahren finden Sie hier

Dies ist ein Beispiel dafür, wie es genannt werden kann:

declare @p5 int  set @p5=86400 
exec DenormV2.udpProductBulletPointSelectByTier1NoteTypeCode
@Tier1=N'WW099',
@LanguageID=3,
@SeasonItemID=N'16AUT',
@ListNoteTypeCode=N'<BulletPoint><NoteTypeCode>GarmentComposition</NoteTypeCode><NoteTypeCode>FootwearAccessoryComposition</NoteTypeCode></BulletPoint>',
@CacheDuration=@p5 output  select @p5

Frage:

Was ist der beste Weg, um herauszufinden, ob der Parameter @ListNoteTypeCode XMLleer ist oder nicht ?

Was ist, wenn sie diese Prozedur so nennen:

declare @p5 int  set @p5=86400 
exec DenormV2.udpProductBulletPointSelectByTier1NoteTypeCode
@Tier1=N'WW099',
@LanguageID=3,
@SeasonItemID=N'16AUT',
@ListNoteTypeCode=N'',
@CacheDuration=@p5 output  select @p5

Wie hier vorgeschlagen , konnte ich die Auswahl durch Testen des Parameters insgesamt vermeiden @ListNoteTypeCode.

Mein Hauptziel in diesem Szenario ist es, die Daten mit der bestmöglichen Leistung abzurufen, da dieses Verfahren nicht auf den Webservern zwischengespeichert wird und über eine Million Mal am Tag aufgerufen wird.

Marcello Miorelli
quelle

Antworten:

7

Sie können prüfen, ob NULLKnoten vorhanden sind ( existTypmethode xml):

@ListNoteTypeCode is NULL OR @ListNoteTypeCode.exist('*') = 0

Ihr XPath kann bei Bedarf spezifischer sein:

@ListNoteTypeCode is NULL OR @ListNoteTypeCode.exist('/BulletPoint/NoteTypeCode/text()') = 0
ich ein
quelle
спасибо Большое. Вы думаете, так это более быстрое выполнение? пожалуйста, может объяснить более
Marcello Miorelli
1
@marcellomiorelli Lass uns Englisch verwenden, weil andere (die vielleicht auch interessiert sind) es vielleicht nicht verstehen (danke für das Russisch!). Ist Ihre Frage zur Prüfung selbst (hilft es, die Prozedur schneller auszuführen oder nicht)? Oder geht es um '*'vs '/BulletPoint/NoteTypeCode/text()'?
i-one
@marcellomiorelli Die Prüfung selbst kann dazu beitragen, die Prozedur schneller auszuführen, falls die angegebene xmlInstanz leer ist. In diesem Fall wird SqlServer keine Ressourcen für die nachfolgende selectKompilierung von Anweisungen (oder eine mögliche Neukompilierung) und Ausführung ausgeben. Stattdessen kann eine "leere" select-Anweisung ausgeführt werden (was viel einfacher ist), wie in Beantwortung einer der vorherigen Fragen vorgeschlagen.
i-one
1
@marcellomiorelli In Bezug auf die '*'vs '/BulletPoint/NoteTypeCode/text()'. Es geht in erster Linie um Semantik. Wenn eine bestimmte xmlInstanz keine anderen als die angegebenen Knoten enthalten kann, '*'kann eine Überprüfung ausreichend sein. Wenn die bereitgestellte xmlInstanz jedoch andere als die angegebenen Knoten enthalten kann und Sie nur einen Teil dieser xmlInstanz verwenden, sollten Sie in Ihrem XPath genauer angeben, ob die angegebene Instanz für den Zweck dieses gespeicherten Prozesses leerxml ist .
i-one
Ich werde die Frage aktualisieren, sobald ich diese Änderung implementieren und testen kann
Marcello Miorelli
3

Eine andere Möglichkeit, auf einen leeren XML-Parameter, eine leere Variable oder eine leere XML-Spalte zu testen, besteht darin, die zu überprüfen DATALENGTH. Jedes leere XML-Element sollte 5 Byte groß sein. Zum Beispiel:

DECLARE @Test TABLE (XmlParam XML NULL);
INSERT INTO @Test ([XmlParam]) VALUES (NULL), (N''), (N'g');

SELECT t.[XmlParam],
       DATALENGTH(t.[XmlParam]) AS [DATALENGTH],
       CASE (ISNULL(DATALENGTH(t.[XmlParam]), 5))
          WHEN 5 THEN 'EMPTY'
          ELSE 'Not Empty'
       END AS [IsEmpty]
FROM   @Test t;

Kehrt zurück:

XmlParam     DATALENGTH    IsEmpty
--------     ----------    ---------
NULL         NULL          EMPTY
             5             EMPTY
g            9             Not Empty

Bitte beachten Sie, dass ich dies verwendet habe ISNULL(DATALENGTH(t.[XmlParam]), 5), um einen Parameter oder eine Variable zu überprüfen. Wenn Sie eine Spalte überprüfen, ist es möglicherweise besser, sie zu verwenden XmlColumn IS NULL OR DATALENGTH(XmlColumn) = 5.

Bitte beachten Sie auch , dass , während es ist möglich für die interne Darstellung von XML - Daten auf Wechsel zwischen Versionen, ich auf SQL Server 2008 R2 getestet habe, 2012 und 2014 und die Größe eines leeren XML - Elements ist konsequent 5.

Solomon Rutzky
quelle
Ich frage mich, ob das schneller wäre (weniger Benutzerressourcen, CPU-Zyklen) als @ ListNoteTypeCode.exist ('*') = 0
Marcello Miorelli
1
@marcellomiorelli Mein Bauchgefühl ist, dass das Überprüfen DATALENGTHschneller ist als das Aufrufen des XML-Parsers, ABER ich habe es nicht getestet. Es sollte jedoch einfach zu testen sein, indem eine Ergebnismenge von 1 Million Zeilen (CROSS JOIN sys.all_columns) generiert und meine Version eingeschlossen wird. Entfernen Sie diese und führen Sie sie erneut mit der i-one-Version aus. Bitte posten Sie die Ergebnisse.
Solomon Rutzky
Wie haben Sie herausgefunden, dass die Größe eines leeren XML 5 beträgt?
Marcello Miorelli
Sie können es hier
Marcello Miorelli
Ich habe die Ergebnisse des Vergleichs hier veröffentlicht. Bitte schauen Sie, wenn Sie eine Chance bekommen.
Marcello Miorelli
0

Mein XML verwendet Schema.
DATALENGTHwird definitiv nicht funktionieren.
Selbst ohne Daten nimmt das Schema immer noch zufällig Speicherplatz ein.

Dies wird auf fehlende Elemente / Knoten testen (funktioniert mit oder ohne Schema):

SELECT ISNULL(@ListNoteTypeCode.exist('*:BulletPoint/*:NoteTypeCode'), 0)[HasRows]

Damit war der Zweck Ihrer Frage, die Leistung zu verbessern.
Sie verwenden eine Correlated-SubQuery!  : O
Huch! Verschieben Sie das in eine Tabellenvariable mit aktiviertem PK NoteTypeCode.
Dann Inner-Join zu Ihrer Tabellenvariablen und vergessen Sie all dieses Test-For-Missing-Xml- Geschäft.

MikeTeeVee
quelle