sql >> Database >  >> RDS >> Sqlserver

XML-gegevens opslaan in SQL Server

Bij het werken aan de release van dbForge Transaction Log, onder andere taken, moest ons team puzzelen hoe getypte XML-gegevens correct op te slaan.

Om te beginnen is het vermeldenswaard dat SQL Server XML niet opslaat in het formaat waarin het is ingevoerd. Een XML-tekenreeks wordt geparseerd, gesplitst in tags en dus opgeslagen in een gecomprimeerd formaat. Beschrijvingselementen die de server als onnodig beschouwt, worden weggegooid.

Houd er ook rekening mee dat, als het gegevenstype van een kolom is opgegeven als eenvoudige XML, de server deze gegevens opslaat als Unicode-tekenreeksen.
Voorbeeld 1.

CREATE TABLE XmlValuesTable (
  [uid] [int] IDENTITY PRIMARY KEY,
  v XML NOT NULL );
GO
INSERT INTO XmlValuesTable (v)
VALUES ('<note><float>123.456</float><time>01:23:45.789</time></note>');
INSERT INTO XmlValuesTable (v)
VALUES ('<note><float>4.0000000000</float><time>01:23:45Z</time></note>');

De server slaat de insert . op gegevens als volgt:

F0 04 6E006F0074006500 <- Name "note"
EF 000001 <- Namespace 01
F8 01 <- tag 01
F0 05 66006C006F0061007400 <- Name "float"
EF 000002 <- Namespace 02
F8 02 <- tag 02
11 07 3100320033002E00340035003600 <- string "123.456"
F7 <- closing tag
F0 04 740069006D006500 <- Name "time"
EF 000003 <- Namespace 02
F8 03 <- tag 03
11 0C 300031003A00320033003A00340035002E00370038003900 <- string "01:23:45.789"
F7 <- closing tag
F7 <- closing tag

In het volgende voorbeeld wordt het kolomgegevenstype gespecificeerd zoals getypt via XML Schema Collection.

Voorbeeld 2.

CREATE XML SCHEMA COLLECTION [XmlValuesSchemaCollection_datetime2] AS
'<?xml version="1.0"?> 
<xsd:schema
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes"

  <xsd:element name="datetime2" type="sqltypes:datetime2"/> 
</xsd:schema>';
GO

CREATE TABLE XmlValuesTable_datetime2 (
  [uid] [int] IDENTITY PRIMARY KEY,
  v XML(XmlValuesSchemaCollection_datetime2) NOT NULL
);
GO

INSERT INTO XmlValuesTable_datetime2 (v)
VALUES (N'<datetime2>2014-06-18T06:39:05.190</datetime2>');
GO

In dit specifieke geval zal de server de insert . opslaan gegevens als volgt:

EA 09 014C010015 1A000000 <- type info 0x14C (332) “datetime2”, 0x15 (21) “dateTime” + offset
F0 09 6400610074006500740069006D0065003200 <- Name "datetime2"
EF 000001 <- Namespace 01
F8 01 <- tag 01
EA 05 004C010015 <- type info
7E 02978924A9380B <- "2014-06-18T06:39:05.190"
F7 <- closing tag

Op deze manier converteert de server de opgeslagen gegevens naar typen die zijn gespecificeerd in het addendum bij dit artikel (u kunt de lijst met alle gegevenstypen bekijken door de query "select * from sys.xml_schema_types" op de server uit te voeren).

Laten we eens kijken hoe de server een complexere structuur zal opslaan, vergelijkbaar met die in voorbeeld 1 en beschreven met XML Schema Collection.

Voorbeeld 3.

CREATE XML SCHEMA COLLECTION [XmlValuesSchemaCollection] AS
'<?xml version="1.0"?>
<xsd:schema
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes"
  attributeFormDefault="unqualified" elementFormDefault="qualified"> 
  <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes"
schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sql2008/sqltypes.xsd"/>

    <xsd:element name="note"> 
     <xsd:complexType> 
       <xsd:sequence> 
          <xsd:element name="float" type="xsd:float"/> 
          <xsd:element name="time" type="xsd:time"/> 
       </xsd:sequence> 
     </xsd:complexType> 
  </xsd:element> 
</xsd:schema>'; 
GO 

CREATE TABLE XmlValuesTable (
  [uid] [int] IDENTITY PRIMARY KEY,
  v XML(XmlValuesSchemaCollection) NOT NULL
);
GO

INSERT INTO XmlValuesTable (v)
VALUES ('<note><float>123.456</float><time>01:23:45.789</time></note>');

De server slaat de insert . op gegevens als volgt:

EA 05 0001000100 <- type info
F0 04 6E006F0074006500 <- Name "note"
EF 000001 <- Namespace
F8 01 <- tag 01
EA 09 0111000011 12000000 <- type info 0x11 (17) "float" + offset
F0 05 66006C006F0061007400 <- Name "float"
EF 000002 <- Namespace
F8 02 <- tag 02
EA 05 0011000011 <- type info 0x11 (17) "float"
03 79E9F642 <- "123.456"
F7 <- closing tag
EA 09 0116000016 10000000 <- type info 0x16 (22) "time" + offset
F0 04 740069006D006500 <- Name "time"
EF 000003 <- Namespace
F8 03 <- tag 03
EA 05 0016000016 <- type info 0x16 (22) "time"
7D 03FDAF4C005B950A <- "01:23:45.789"
F7 <- closing tag
F7 <- closing tag

Laten we proberen een schemalink aan de bijlage toe te voegen.

Voorbeeld 4.

INSERT INTO XmlValuesTable (v)
VALUES ('<note xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><float>123.456</float><time>01:23:45.789</time></note>');
EA 05 0001000100 <- type info
F0 04 6E006F0074006500 <- Name "note"
EF 000001 <- Namespace
F8 01 <- tag 01
F0 09 78006D006C006E0073003A00780073006900 <- Name "xmlns:xsi"
EF 000200 <- Namespace "xmlns:xsi"
F6 02 <- Attribute
11 29 68007400740070003A002F002F007700770077002E00770033002E006F00720067002F0032003000300031002F0058004D004C0053006300680065006D0061002D0069006E007300740061006E0063006500 <- "http://www.w3.org/2001/XMLSchema-instance"
F5 <- closing bracket
EA 09 0111000011 12000000 <- type info 0x11 (17) "float" + offset
F0 05 66006C006F0061007400 <- Name "float"
EF 000003 <- Namespace
F8 03 <- tag 03
EA 05 0011000011 <- type info 0x11 (17) "float"
03 79E9F642 <- "123.456"
F7 <- closing tag
EA 09 0116000016 10000000 <- type info 0x16 (22) "time" + offset
F0 04 740069006D006500  <- Name "time"
EF 000004 <- Namespace
F8 04 <- tag 08
EA 05 0016000016 <- type info 0x16 (22) "time"
7D 03FDAF4C005B950A <- "01:23:45.789"
F7 <- closing tag
F7 <- closing tag

Zoals je kunt zien, heeft de server de naamruimte zorgvuldig als een attribuut opgeslagen en bijna de helft van de ruimte hiervoor gebruikt, ondanks het feit dat de naamruimte hier niet echt een nuttig doel heeft - de gegevens werden op dezelfde manier opgeslagen als het zou zijn opgeslagen zonder de naamruimte.

Conclusie

Uit het bovenstaande kan het lijken alsof u de grootte van een database kunt verkleinen door sommige gegevenstypen (bijv. float) als getypte waarden op te slaan, aangezien 4 bytes aanzienlijk minder opslagruimte nodig hebben dan dezelfde waarde die is opgeslagen als een Unicode-reeks. Houd er echter rekening mee dat voor elke waarde extra 7-18 bytes worden gebruikt om het type te beschrijven en naar de gewenste positie te verplaatsen.

Aanvulling

Correlatie van XML-typen, basistypen en gegevenstypen die de server gebruikt om getypte waarden op te slaan.

XML-type Basistype Opgeslagen als type Grootte in bytes
anyType tekenreeks 2 * tekens
anySimpleType anyType tekenreeks
tekenreeks anySimpleType tekenreeks
booleaans anySimpleType booleaans 1
zweven anySimpleType zweven 4
dubbel anySimpleType dubbel 8
decimaal anySimpleType SqlDecimaal 20
duur anySimpleType tekenreeks
dateTime anySimpleType *1
tijd anySimpleType *1
datum anySimpleType *1
gYearMonth anySimpleType tekenreeks
gYear anySimpleType tekenreeks
gMonthDay anySimpleType tekenreeks
gDay anySimpleType tekenreeks
gMaand anySimpleType tekenreeks
hexBinair anySimpleType array van bytes
base64Binary anySimpleType array van bytes
anyURI anySimpleType tekenreeks
QNaam anySimpleType tekenreeks
normalizedString tekenreeks tekenreeks
token tekenreeks tekenreeks
taal tekenreeks tekenreeks
Naam tekenreeks tekenreeks
NCNaam tekenreeks tekenreeks
ENTITEIT tekenreeks tekenreeks
NMTOKEN tekenreeks tekenreeks
geheel getal decimaal SqlDecimaal 20
nonPositiveInteger geheel getal SqlDecimaal 20
negativeInteger nonPositiveInteger SqlDecimaal 20
lang geheel getal SqlDecimaal 20
int lang SqlDecimaal 20
kort int SqlDecimaal 20
byte kort SqlDecimaal 20
nonNegativeInteger geheel getal SqlDecimaal 20
unsignedLang niet-negatief geheel getal SqlDecimaal 20
unsignedInt unsignedLang SqlDecimaal 20
unsignedShort unsignedInt SqlDecimaal 20
unsignedByte unsignedShort SqlDecimaal 20
positiefGeheel getal niet-negatief geheel getal SqlDecimaal 20
char tekenreeks tekenreeks
nchar tekenreeks tekenreeks
varchar tekenreeks tekenreeks
nvarchar tekenreeks tekenreeks
tekst tekenreeks tekenreeks
ntext tekenreeks tekenreeks
varbinair base64Binary array van bytes
binair base64Binary array van bytes
afbeelding base64Binary array van bytes
tijdstempel base64Binary array van bytes
timestampNumeric lang SqlDecimaal 20
numeriek decimaal SqlDecimaal 20
groot lang SqlDecimaal 20
smallint kort SqlDecimaal 20
tinyint unsignedByte SqlDecimaal 20
bit booleaans booleaans 1
echt zweven zweven 4
datumtijd dateTime *1
smalldatetime dateTime *1
geld decimaal SqlDecimaal
klein geld decimaal SqlDecimaal
unieke identificatie decimaal tekenreeks
datetime2 dateTime *1
datetimeoffset dateTime *1
hiërarchie tekenreeks tekenreeks
dbobject anyURI tekenreeks

*1 – gegevens/tijdinformatie. Het specifieke type wordt bepaald door de waarde.

Waarde Opgeslagen als type Grootte in bytes
Datumverschuiving Datum (aantal dagen) 3
DateOffset (2019-09-16+02:00) DateTimeOffset 11
DateTime DateTime 7-9 hangt af van precisie
DateTimeOffset DateTimeOffset 9
Tijd DateTime 7-9 hangt af van precisie
TimeOffset (01:23:45Z) DateTimeOffset 9

  1. MySQL verwijdert duplicaten snel uit grote database

  2. Hetzelfde schema gebruiken voor meerdere SQL Server Agent-taken (T-SQL)

  3. Hoe de ORA-00936 ontbrekende uitdrukking op te lossen?

  4. Oracle-aliasing begrijpen - waarom wordt een alias niet herkend in een query, tenzij verpakt in een tweede query?