[1] Dacă este vorba de SQL2008 atunci
sparse columns (dupa cum a recomandat si Andrei).
Uite o comparatie
sparse columns vs.
XML netipizat vs.
XML tipizat.
La mine scorul a fost următorul:
sparse columns 80.922 MB
XML netipizat 140.484 MB
XML tipizat 181.703 MBCREATE TABLE Persoana1
(
IDPersoana INT IDENTITY(1,1) PRIMARY KEY,
Nume VARCHAR(50) NOT NULL,
DataNasterii DATETIME SPARSE NULL,
Greutate DECIMAL SPARSE NULL,
Nevasta VARCHAR(50) SPARSE NULL,
Copii INT SPARSE NULL
);
GO
CREATE TABLE Persoana2
(
IDPersoana INT PRIMARY KEY,
Nume VARCHAR(50) NOT NULL,
Alte XML NOT NULL
);
GO
CREATE XML SCHEMA COLLECTION XMLAlte AS
'<?xml version="1.0" encoding="utf-8" ?>
<xs:schema blockDefault="" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="TipAlteInformatii">
<xs:choice>
<xs:element name="DataNasterii" type="xs:string" />
<xs:element name="Greutate" type="xs:decimal" />
<xs:sequence>
<xs:element name="Nevasta" type="xs:string" />
<xs:element name="Copii" type="xs:integer" />
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:element name="Alte" type="TipAlteInformatii" />
</xs:schema>';
GO
CREATE TABLE Persoana3
(
IDPersoana INT PRIMARY KEY,
Nume VARCHAR(50) NOT NULL,
Alte XML (XMLAlte) NOT NULL
);
GO
DECLARE @i INT
SET @i=1
WHILE @i <= 1000000
BEGIN
DECLARE @tipPersoana INT
SET @tipPersoana = ABS( CAST( CAST( NEWID() AS VARBINARY ) AS INT) )
IF @tipPersoana % 3 = 0
INSERT INTO Persoana1 ( Nume, DataNasterii ) VALUES ( NEWID(), CAST( CAST( CAST( NEWID() AS VARBINARY ) AS SMALLINT ) AS DATETIME ) )
ELSE
IF @tipPersoana % 3 = 1
INSERT INTO Persoana1 ( Nume, Greutate ) VALUES ( NEWID(), CAST( RAND()*1000000 AS INT )%100 )
ELSE
IF @tipPersoana % 3 = 2
INSERT INTO Persoana1 ( Nume, Nevasta, Copii ) VALUES ( NEWID() , NEWID() , CAST( RAND()*1000000 AS INT )%10 )
SET @i = @i + 1
END
GO
SELECT COUNT(*) AS NrTabelaPersoana1 FROM Persoana1
GO
INSERT INTO Persoana2
SELECT IDPersoana,
Nume,
'<Alte>'+
CASE
WHEN DataNasterii IS NOT NULL THEN '<DataNasterii>'+CAST(DataNasterii AS VARCHAR(25))+'</DataNasterii>'
WHEN Greutate IS NOT NULL THEN '<Greutate>'+CAST(Greutate AS VARCHAR(25))+'</Greutate>'
WHEN Nevasta IS NOT NULL THEN '<Nevasta>'+Nevasta+'</Nevasta> <Copii>'+CAST(Copii AS VARCHAR(2))+'</Copii>'
END+
'</Alte>'
FROM Persoana1
GO
SELECT COUNT(*) AS NrTabelaPersoana2 FROM Persoana2
GO
INSERT INTO Persoana3 (IDPersoana,Nume,Alte)
SELECT IDPersoana,
Nume,
'<Alte>'+
CASE
WHEN DataNasterii IS NOT NULL THEN '<DataNasterii>'+CAST(DataNasterii AS VARCHAR(25))+'</DataNasterii>'
WHEN Greutate IS NOT NULL THEN '<Greutate>'+CAST(Greutate AS VARCHAR(25))+'</Greutate>'
WHEN Nevasta IS NOT NULL THEN '<Nevasta>'+Nevasta+'</Nevasta> <Copii>'+CAST(Copii AS VARCHAR(2))+'</Copii>'
END+
'</Alte>'
FROM Persoana1
GO
SELECT COUNT(*) AS NrTabelaPersoana3 FROM Persoana3
GO
EXEC sp_spaceused 'dbo.Persoana1'
EXEC sp_spaceused 'dbo.Persoana2'
EXEC sp_spaceused 'dbo.Persoana3'[2] Pentru SQL < 2008 : partitionare pe orizantala > trei tabele separate + view cu union all +
eventual triger-e INSTEAD OF INSERT/ DELETE/ UPDATE