Frage

Hintergrund

Vor kurzem habe ich zu verwenden XML viel mehr als eine Spalte in SQL Server 2005. Während ein wenig Ausfallzeiten gestern begann, bemerkte ich, dass zwei der Link-Tabellen ich wirklich nur in der Art und Weise verwendet, und es langweilt mich zu Tränen, die noch mehr schreiben von Verknüpfungen für ein paar Strukturcode zu unterstützen.

Zur Erzeugung tatsächlich die Daten für diese beiden Link-Tabellen, gebe ich in zwei XML-Felder meiner gespeicherten Prozedur, die den Hauptsatz schreibt, bricht die beiden XML-Variablen nach unten in @tables und fügt sie in die tatsächlichen Tabellen mit der neuen SCOPE_IDENTITY() aus dem Stammsatz.

Nach einiger obwohl habe ich beschlossen, mit diesen Tabellen ganz einfach zu tun, weg und speichern nur die XML in XML-Feldern. Jetzt verstehe ich, es gibt einige Fallen hier, wie allgemeine anfragende Leistung, nicht GROUP BY nicht auf XML-Daten arbeiten. Und die Abfrage ist in der Regel ein bisschen ein Durcheinander, aber insgesamt Ich mag, dass ich kann jetzt die Arbeit mit XElement, wenn ich die Daten wieder bekommen.

Auch ist dieses Zeug wird nicht umziehen. Es ist ein One-Shot-Affäre, so habe ich nicht zu befürchten Änderung.

Ich frage mich, über den besten Weg, um tatsächlich an diesen Daten. Viele meiner Anfragen beinhalten immer einen Stammsatz auf die Kriterien eines Kindes basiert oder sogar ein subchild Rekord. Die meisten der sprocs in der Datenbank tun dies aber auf eine weit aufwändigere Skala, in der Regel benutzerdefinierte Funktionen und Unterabfragen an die Arbeit effektiv erfordern, aber ich habe ein triviales Beispiel zu Test Abfrage einige Daten ...

geschwängert
INSERT INTO Customers VALUES ('Tom', '', '<PhoneNumbers><PhoneNumber Type="1" Value="01234 456789" /><PhoneNumber Type="2" Value="01746 482954" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Andy', '', '<PhoneNumbers><PhoneNumber Type="2" Value="07948 598348" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Mike', '', '<PhoneNumbers><PhoneNumber Type="3" Value="02875 482945" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Steve', '', '<PhoneNumbers></PhoneNumbers>')

Jetzt kann ich zwei Möglichkeiten sieht sie packt.

Methode 1

DECLARE @PhoneType INT
SET  @PhoneType = 2

SELECT ct.*
FROM Customers ct
WHERE ct.PhoneNumbers.exist('/PhoneNumbers/PhoneNumber[@Type=sql:variable("@PhoneType")]') = 1

Wirklich? sql: variable fühlt sich ein bisschen ungesund. Allerdings funktioniert es. Allerdings ist es deutlich schwieriger, den Zugriff auf Daten in einer sinnvollen Weise.

Methode 2

SELECT ct.*, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') = @PhoneType

Das ist mehr wie es. Schon kann ich erweitern es leicht zu tun verbindet und alle anderen guten Sachen. Ich habe CROSS APPLY vor auf einem Tisch Wertfunktion verwendet, und es war sehr gut. Der Ausführungsplan für diesen in Bezug auf die vorherige Abfrage Gegensatz ist ernsthaft weiter fortgeschritten. Zwar habe ich keine Indizierung und so weiter auf diesen Tabellen getan, aber es ist 97% der gesamten Charge Kosten.

Methode 2 (erweitert)

SELECT ct.ID, ct.CustomerName, ct.Notes, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') IN (SELECT ID FROM PhoneTypes)

Nizza IN Klausel hier. Ich kann auch so etwas wie pt.PhoneType = 'Work' tun

Schließlich

Also habe ich im Wesentlichen bin die Ergebnisse zu erhalten, dass ich will, aber ist es etwas, was ich bewusst sein sollte, wenn dieser Mechanismus mit kleinen Mengen von XML-Daten abzufragen? Wird es auf die Leistung während der aufwendigen Suche nach unten fallen? Und ist die Speicherung solcher Markup Stildaten zu viel von einem Overhead?

Side Hinweis:

Ich habe Dinge wie sp_xml_preparedocument und OPENXML in der Vergangenheit nur Listen in sprocs passieren, aber das ist wie ein Hauch frischer Luft im Vergleich!

War es hilfreich?

Lösung

One approach we've taken for some of our key items of information stored inside an XML column is to "surface" them as computed, persisted properties on the "parent" table. This is done using a little stored function.

It works great, because the value is computed only once every time the XML changes - as long as it's not changing, there's no recomputation, the value is stored on the table like any other column.

It's also great since it can be indexed! So if you're searching and/or joining on such a field - that works like a charm!

So you basically need a stored function along the lines of this:

CREATE FUNCTION [dbo].[GetPhoneNo1](@DataXML XML)
RETURNS VARCHAR(50)
WITH SCHEMABINDING
AS BEGIN
      DECLARE @result VARCHAR(20)

      SELECT 
        @result = @DataXML.value('(/PhoneNumbers/PhoneNumber[@Type="1"]/@Value)[1]', 'VARCHAR(50)')
      RETURN @result
END

If you don't have a phone number of type 1, you'll just get back a NULL.

Then, you need to extend your parent table with a computed, persisted column:

ALTER TABLE dbo.Customers
   ADD PhoneNumberType1 AS dbo.GetPhoneNo1(PhoneNumbers)

As you can see - it works just fine for single entries, but unfortunately, you cannot surface a whole list of properties. But if you have some key items, like ID's or something, that you expect most of your rows to have, this can be a very nice and slick way to get at that information more easily and more efficiently.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top