Warnung vor impliziter Konvertierung

7

Ich habe eine Tabelle mit 2 Namensspalten:

CREATE TABLE Test
(
  TestID int identity primary key clustered
  , Name_Eng nvarchar(50)
  , Name_Nat nvarchar(50)
)

Jetzt brauche ich eine Abfrage, um diese NameSpalte ,wie folgt zu trennen :

    DECLARE @NameColumns NVARCHAR(1024)

            SET @NameColumns = STUFF(
      (SELECT   ',' + 'Test.' + name AS [text()]
       FROM     ( SELECT    c.name
                  FROM      sys.columns c 
                            INNER JOIN sys.tables t ON t.object_id = c.object_id
                  WHERE     t.name = 'Test'
                            AND c.name LIKE 'Name_%'
                ) AS D
                FOR                  XML PATH('') ,
                                         TYPE).value('.[1]', 'VARCHAR(MAX)'), 1, 1,
                                     N'')

select  @NameColumns

Diese Abfrage enthält jedoch eine Warnung im Ausführungsplan:

implizite Konvertierungswarnung

Gibt es eine Möglichkeit, diese Warnung zu entfernen?

Artashes Khachatryan
quelle

Antworten:

9

Die Warnung ist aufgrund der XML-Funktion vorhanden value(). Der zweite Parameter value()ist, in den der in XML gespeicherte Wert konvertiert werden soll. Sie könnten argumentieren, dass dies tatsächlich keine implizite Konvertierung ist, sondern eine sehr explizite Konvertierung, da Sie darum bitten, dass dies geschieht. Vielleicht etwas, das ein Verbindungselement Microsoft vorschlagen kann.

Einfachste Möglichkeit, das zu reproduzieren, was Sie sehen.

declare @X xml;
select @X.value('text()[1]', 'int');

Gibt diese beiden Warnungen.

<Warnings>
    <PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)" />
    <PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)" />
</Warnings>

Wie Sie sehen können, erhalten Sie es auch mit int's und Sie erhalten zwei davon für jeden Aufruf von value().

declare @X xml;
select @X.value('text()[1]', 'int'),
       @X.value('text()[1]', 'bit');
<Warnings>
    <PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)" />
    <PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)" />
    <PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(bit,XML Reader with XPath filter.[lvalue],0)" />
    <PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(bit,XML Reader with XPath filter.[value],0)" />
</Warnings>

Die Konvertierung erfolgt im Stream Aggregate-Operator, der den Wert wie folgt berechnet.

MIN(CASE WHEN [@X] IS NULL 
      THEN NULL 
      ELSE 
      CASE WHEN datalength(XML Reader with XPath filter.[value])>=(128) 
        THEN CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0) 
        ELSE CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0) 
      END 
    END)

Das Ergebnis der Funktion "Tabellenwert" wird in der Spalte lvalueoder zurückgegeben value. Der Ausdruck prüft, indem er verwendet, datalengthum herauszufinden, woher er abgerufen werden soll, und konvertiert ihn dann in den gewünschten Datentyp.

Gibt es eine Möglichkeit, diese Warnung zu entfernen?

Ja da ist. Sie entfernen die TYPEDirektive aus der FOR XML PATHAnweisung und entfernen den Aufruf der value()Funktion. Ein Nebeneffekt dabei ist, dass von Ihnen verkettete Werte, die Zeichen enthalten, die wie in XML &<>codiert werden müssen, in Ihrem Ergebnis codiert werden.

Mikael Eriksson
quelle
9

Obwohl ich @Kin in Bezug auf Datentypen zustimme, halte ich diese Warnung nicht für so problematisch wie Sie denken. Sie führen eine gruppierte Verkettung durch, die ohnehin um Größenordnungen teurer sein wird als alle Konvertierungen (und wie Daniel sagte, ist es unwahrscheinlich, dass sich dies auf irgendetwas auswirkt, es sei denn, Ihre Katalogansichten sind massiv - wie in einem größeren als dem physischen Speicher Schätzung entweder).

Ich würde die Abfrage auf diese Weise schreiben und darauf achten, niemals varchar-Zeichenfolgen zu verwenden (was auch bedeutet, das NPräfix für Zeichenfolgenliterale nicht mehr wegzulassen) und auch sicherzustellen, dass Sie Anweisungsabschlusszeichen verwenden :

DECLARE @NameColumns nvarchar(max); -- why 1024 when you use max below?

SET @NameColumns = STUFF(
  (SELECT   N',Test.' + name AS [text()] FROM    
    (
      SELECT c.name FROM sys.columns AS c 
        INNER JOIN sys.tables AS t 
          ON t.object_id = c.object_id
        WHERE t.name = N'Test'
        AND   c.name LIKE N'Name_%'
    ) AS D FOR XML PATH(N''),
    TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'');

SELECT @NameColumns;

Trotzdem glaube ich nicht, dass es eine Möglichkeit gibt, die implizite Konvertierung zu vermeiden, ohne die Ausgabe zu ändern, indem TYPE/ vermieden wird, value()wie Mikael vorgeschlagen hat . Ich würde sagen, machen Sie sich darüber Sorgen, wenn Sie tatsächlich nachweisen können, dass dies einen wesentlichen Einfluss auf die Leistung der Abfrage hat. In meinen Tests haben die beiden verschiedenen Formen die gleiche Leistung erbracht (wir sprechen jedes Mal unter 10 ms), aber wenn ich eine Tabelle mit dem Namen Sales & Stuffhabe, wird sie natürlich Sales &amp; Stuffohne die implizite Konvertierung.

Aaron Bertrand
quelle
3

Die Warnung in der Abfrage - Plan bedeutet , dass , weil Sie eine implizite Datentyp - Konvertierung haben, SQL Server nicht in der Lage sein , genau die richtige Anzahl von Zeilen zu erraten zurückgegeben, was wiederum könnte zu einem weniger als optimalen Plan führen.

Dies ist wichtig bei Abfragen, die eine gute Leistung erbringen müssen, normalerweise, weil sie mit vielen Daten arbeiten. In Ihrer Situation scheint dies jedoch nicht der Fall zu sein, da Sie nur Abfragen durchführen sys.tablesund sys.columns.

Die kurze Antwort auf Ihre Frage lautet: Es spielt keine Rolle, es sei denn, Sie haben Millionen und Abermillionen von Tabellen und Spalten in Ihrer Datenbank.

Daniel Hutmacher
quelle