Ich denke, es ist eine gute Frage - Diese Situation ist ziemlich häufig, obwohl es schwierig ist, Tabellen zu machen, um es zu unterstützen.
In Bezug auf die Leistung verschwendet eine Tabelle wie in # 3 angegeben möglicherweise eine große Menge an Speicher und RAM, da Sie für jede Zeile Speicherplatz für einen Wert von jedem Typ zuweisen, aber nur einen verwenden. Wenn Sie das neue Sparse-Tabellen-Feature von 2008 verwenden, könnte es hilfreich sein, aber es gibt noch andere Probleme: Es ist ein wenig schwierig zu beschränken/normalisieren, weil nur einer der mehreren Werte für jede Zeile gefüllt werden soll - mit zwei Werten in zwei Spalten wäre ein Fehler, aber das Design spiegelt das nicht wider. Ich würde das durchkreuzen. Wenn ich das wäre, würde ich nach Option 1 oder 2 oder 4 suchen, und die Entscheidung würde davon ausgehen: Muss ich normalerweise eine Abfrage erstellen, die Zeilen zurückgibt, die einen Mix von Werten haben von verschiedenen Typen in der gleichen Ergebnismenge?Oder werde ich fast immer nach den Zeilen nach Artikel und nach Typ fragen. Ich frage, denn wenn die Werte verschiedene Typen sind, bedeutet das für mich einen Unterschied in der Quelle oder der Verwendung dieser Daten (es ist zum Beispiel unwahrscheinlich, dass Sie eine Zeichenkette und eine reale Zeichenkette oder eine Zeichenkette und ein Bit miteinander vergleichen) Dies ist wichtig, da unterschiedliche Tabellen pro Typ möglicherweise einen erheblichen Leistungs-/Skalierbarkeitsvorteil darstellen, wenn die Daten auf diese Weise schneller verarbeitet werden. Das Partitionieren von Daten in kleinere Sätze enger verwandter Daten kann einen Leistungsvorteil ergeben.
Es ist so, als hätten wir alle Daten in einem großen (wenn auch sortierten) Satz oder in kleinere, zusammengehörige Mengen unterteilt. Die kleineren Sätze bevorzugen einige Arten von Abfragen, und wenn dies die Abfragen sind, die Sie benötigen, ist es ein Gewinn.
Details:
CREATE TABLE [dbo].[items](
[itemid] [int] IDENTITY(1,1) NOT NULL,
[item] [varchar](100) NOT NULL,
CONSTRAINT [PK_items] PRIMARY KEY CLUSTERED
(
[itemid] ASC
)
)
/* This table has the problem of allowing two values
in the same row, plus allocates but does not use a
lot of space in memory and on disk (bad): */
CREATE TABLE [dbo].[vals](
[itemid] [int] NOT NULL,
[datestamp] [datetime] NOT NULL,
[valueBit] [bit] NULL,
[valueNumericA] [numeric](2, 0) NULL,
[valueNumericB] [numeric](8, 2) NULL,
[valueReal] [real] NULL,
[valueString] [varchar](100) NULL,
CONSTRAINT [PK_vals] PRIMARY KEY CLUSTERED
(
[itemid] ASC,
[datestamp] ASC
)
)
ALTER TABLE [dbo].[vals] WITH CHECK
ADD CONSTRAINT [FK_vals_items] FOREIGN KEY([itemid])
REFERENCES [dbo].[items] ([itemid])
GO
ALTER TABLE [dbo].[vals] CHECK CONSTRAINT [FK_vals_items]
GO
/* This is probably better, though casting is required
all the time. If you search with the variant as criteria,
that could get dicey as you have to be careful with types,
casting and indexing. Also everything is "mixed" in one
giant set */
CREATE TABLE [dbo].[allvals](
[itemid] [int] NOT NULL,
[datestamp] [datetime] NOT NULL,
[value] [sql_variant] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[allvals] WITH CHECK
ADD CONSTRAINT [FK_allvals_items] FOREIGN KEY([itemid])
REFERENCES [dbo].[items] ([itemid])
GO
ALTER TABLE [dbo].[allvals] CHECK CONSTRAINT [FK_allvals_items]
GO
/* This would be an alternative, but you trade multiple
queries and joins for the casting issue. OTOH the implied
partitioning might be an advantage */
CREATE TABLE [dbo].[valsBits](
[itemid] [int] NOT NULL,
[datestamp] [datetime] NOT NULL,
[val] [bit] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[valsBits] WITH CHECK
ADD CONSTRAINT [FK_valsBits_items] FOREIGN KEY([itemid])
REFERENCES [dbo].[items] ([itemid])
GO
ALTER TABLE [dbo].[valsBits] CHECK CONSTRAINT [FK_valsBits_items]
GO
CREATE TABLE [dbo].[valsNumericA](
[itemid] [int] NOT NULL,
[datestamp] [datetime] NOT NULL,
[val] numeric(2, 0) NOT NULL
) ON [PRIMARY]
GO
... FK constraint ...
CREATE TABLE [dbo].[valsNumericB](
[itemid] [int] NOT NULL,
[datestamp] [datetime] NOT NULL,
[val] numeric (8, 2) NOT NULL
) ON [PRIMARY]
GO
... FK constraint ...
etc...
Ich bin noch am messen. Bisher sind die Optionen 3 und 4 ähnlich: Sie sind ziemlich schnell und benötigen weniger Speicherplatz als 1 und 2. Geringere Spalten benötigen mehr Platz und sind langsamer. Bei abdeckenden Indizes ist die Leseleistung besser als erwartet. – Recep