Question

Arrière-plan

Récemment, j'ai commencé à utiliser XML beaucoup plus comme une colonne dans SQL Server 2005. Pendant un peu de temps d'arrêt hier, j'ai remarqué que deux des tables de lien que j'ai utilisé un vraiment juste de la manière et il me ennuie à larmes avoir à écrire encore plus le code de la structure de support pour un couple de jointures.

Pour générer réellement les données de ces deux tables de lien, je passe dans deux champs XML à ma procédure stockée, qui écrit le dossier principal, casse les deux variables XML vers le bas dans @Tables et insère-les dans les tableaux réels avec la nouvelle SCOPE_IDENTITY() de la fiche.

Après un certain cependant, j'ai décidé de le faire disparaître ces tables tout à fait et juste stocker les données XML dans les champs XML. Maintenant, je crois savoir qu'il ya quelques pièges ici, comme les performances d'interrogation générale, GROUP BY ne fonctionne pas sur des données XML. Et la requête est généralement un peu plus d'un gâchis, mais je l'ensemble comme ça je peux maintenant travailler avec XElement quand je reçois le dos de données.

En outre, ce genre de choses ne va pas se changer. C'est une affaire de prise de vue, donc je n'ai pas à vous soucier de la modification.

Je me demande au sujet de la meilleure façon d'obtenir effectivement à ces données. Beaucoup de mes requêtes impliquons obtenir un enregistrement maître en fonction des critères d'un enfant ou même un record subchild. La plupart des sprocs dans la base de données font cela, mais à une échelle beaucoup plus élaborée, le plus souvent exigeant et UDFs Subqueries à travailler efficacement mais j'ai frappé un exemple trivial pour tester l'interrogation certaines données ...

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>')

Maintenant, je peux voir deux façons de le saisissant.

Méthode 1

DECLARE @PhoneType INT
SET  @PhoneType = 2

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

Vraiment? sql: Variable se sent un peu insalubre. Cependant, il ne fonctionne pas. Cependant, il est typiquement plus difficile d'accéder aux données d'une manière plus significative.

Méthode 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

Ceci est plus comme ça. Déjà, je peux facilement l'étendre à des jointures et tous les autres bonnes choses. Je l'ai utilisé CROSS APPLY avant sur une fonction d'une valeur de la table, et il était très bon. Le plan d'exécution pour ce par opposition à la requête précédente est sérieusement plus avancé. Il est vrai que je ne l'ai pas fait de l'indexation et ainsi de suite sur ces tables, mais il est de 97% du coût total du lot.

Méthode 2 (élargi)

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)

Nice clause IN ici. Je peux aussi faire quelque chose comme pt.PhoneType = 'Work'

Enfin

Je suis essentiellement obtenir les résultats que je veux, mais est-ce que je devrais être au courant lors de l'utilisation de ce mécanisme pour interroger de petites quantités de données XML? Sera-t-tomber sur la performance au cours des recherches élaborées? Et est le stockage de ces données de style de balisage trop d'une surcharge?

Side note

Je l'ai utilisé des choses comme sp_xml_preparedocument et OPENXML dans le passé juste pour passer des listes dans sprocs, mais c'est comme une bouffée d'air frais par rapport!

Était-ce utile?

La solution

Une approche que nous avons pris pour certains de nos éléments clés d'informations stockées dans une colonne XML est de leur « surface » telle que calculée, ont persisté propriétés sur la table « parent ». Cela se fait à l'aide d'une petite fonction stockée.

Il fonctionne très bien, parce que la valeur est calculée une seule fois à chaque fois que les changements XML -. Tant qu'il ne change pas, il n'y a pas recalcul, la valeur est stockée sur la table comme une autre colonne

Il est également grand car il peut être indexé! Donc, si vous êtes à la recherche et / ou de se joindre à un domaine - qui fonctionne comme un charme

Vous devez donc essentiellement une fonction stockée le long des lignes de celle-ci:

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

Si vous ne disposez pas d'un numéro de téléphone de type 1, vous aurez juste récupérer un NULL.

Ensuite, vous devez étendre votre table parent avec un calculé, la colonne persiste:

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

Comme vous pouvez le voir - il fonctionne très bien pour les entrées simples, mais malheureusement, vous ne pouvez pas la surface d'une liste complète des propriétés. Mais si vous avez des éléments clés, comme d'ID ou de quelque chose, que vous attendez la plupart de vos lignes à avoir, cela peut être une très belle et lisse pour obtenir cette information plus facilement et plus efficacement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top