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 |