Mir ist klar, dass dies möglicherweise als Duplikat markiert ist, aber ich frage speziell in Bezug auf SQL Server 2005
Ich habe widersprüchliche Ratschläge im Internet gelesen und frage hier. Insbesondere in SQL Server 2005 nimmt ein NULL-Wert in einer varchar-Spalte denselben Platz ein wie eine leere Zeichenfolge?
Ich habe eine 'Holding'-Tabelle auf einem anderen Laufwerk erstellt und sie mit den Daten aus der nullif([field],'')
Quelltabelle gefüllt. Wo immer die Felder leer waren, habe ich anstelle der Leerzeichen Nullen eingefügt.
Dann habe ich eine neue Tabelle mit genau der gleichen Struktur wie die Haltetabelle erstellt, aber anstatt Leerzeichen durch Null zu ersetzen, habe ich nur die Leerzeichen eingefügt, und bis jetzt scheint es mehr Platz zu beanspruchen (ich bin noch nicht damit fertig, sie zu füllen und Ich kann nicht sicher sein, ob es noch mehr Daten aufnimmt.)
Bevor ich es weiter fülle und eine Tabelle erhalte, die größer ist als ich dachte, ist es besser, Nullen oder Leerzeichen einzufügen?
Bearbeiten:
Nach der Migration der Daten von der Haltetabelle in die neue Tabelle ist die neue Tabelle ca. 4 GB größer.
Es gibt nur zwei kleine Unterschiede im Tabellendesign: Das Feld 'serial_number' ist char (15) in der Haltetabelle, varchar (15) in der Zieltabelle. (Die maximale Länge einer Seriennummer beträgt 14 und es gibt viele leere Werte - ich denke, wenn ich mich recht erinnere, ungefähr 30 Millionen), und der Clustered-Index für die Haltetabelle hat eine zusätzliche Spalte - program_name ..
Tisch halten
USE [Temp_holding_EWS]
GO
/****** Object: Table [dbo].[AmtoteAccountActivity_holding]
Script Date: 02/17/2017 20:41:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[AmtoteAccountActivity_holding](
[_Date] [char](8) NULL,[Community] [varchar](10) NULL,
[AccountNumber] [varchar](50) NULL,
[Branch] [varchar](10) NULL,
[Window] [varchar](3) NULL,
[Time] [char](8) NULL,[Balance_Forward] [varchar](10) NULL,
[Transaction_Type] [varchar](10) NULL,
[Program_Name] [varchar](10) NULL,
[Race] [varchar](10) NULL,[Pool_Type] [varchar](10) NULL,
[Amount] [money] NULL,[Runners] [varchar](60) NULL,
[Total_Bet_Amount] [varchar](10) NULL,
[Debit_Amount] [varchar](10) NULL,
[Credit_Amount] [varchar](10) NULL,
[Tx_Date] [char](8) NULL,
[Check_Clear_Date] [varchar](10) NULL,
[Refund_Amt] [varchar](10) NULL,
[Bet_Pool_Modifier] [varchar](5) NULL,
[RecordID] [int] IDENTITY(1,1) NOT NULL,
[serial_number] [char](15) NULL,
[handle] AS
(CONVERT([money],[total_bet_amount],(0))-CONVERT([money],[refund_amt],(0))),
[txdatetime] AS (CONVERT([datetime],([tx_date]+' ')+[time],(11))),
[dbdate] AS (CONVERT([datetime],[_date],(11))),
[Audit_Trail] [varchar](20) NULL,
CONSTRAINT [PK_AmtoteAccountActivity_holding] PRIMARY KEY NONCLUSTERED
(
[RecordID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
(Clustered Index)
USE [Temp_holding_EWS]
GO
/****** Object: Index [IX_AmtoteAccountActivity_holding]
Script Date: 02/17/2017 21:08:44 ******/
CREATE CLUSTERED INDEX [IX_AmtoteAccountActivity_holding] ON
[dbo].[AmtoteAccountActivity_holding]
(
[AccountNumber] ASC,
[_Date] ASC,
[Program_Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Zieltabelle
USE [EWS]
GO
/****** Object: Table [dbo].[AmtoteAccountActivity]
Script Date: 02/17/2017 20:48:16 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[AmtoteAccountActivity](
[_Date] [char](8) NULL, [Community] [varchar](10) NULL,
[AccountNumber] [varchar](50) NULL,
[Branch] [varchar](10) NULL,[Window] [varchar](3) NULL,
[Time] [char](8) NULL, [Balance_Forward] [varchar](10) NULL,
[Transaction_Type] [varchar](10) NULL,
[Program_Name] [varchar](10) NULL,
[Race] [varchar](10) NULL,
[Pool_Type] [varchar](10) NULL,
[Amount] [money] NULL,[Runners] [varchar](60) NULL,
[Total_Bet_Amount] [varchar](10) NULL,
[Debit_Amount] [varchar](10) NULL,
[Credit_Amount] [varchar](10) NULL,
[Tx_Date] [char](8) NULL,
[Check_Clear_Date] [varchar](10) NULL,
[Refund_Amt] [varchar](10) NULL,
[Bet_Pool_Modifier] [varchar](5) NULL,
[RecordID] [int] IDENTITY(1,1) NOT NULL,
[serial_number] [varchar](15) NULL,
[handle] AS
(CONVERT([money],[total_bet_amount],(0))-CONVERT([money],[refund_amt],(0))),
[txdatetime] AS (CONVERT([datetime],([tx_date]+' ')+[time],(11))),
[dbdate] AS (CONVERT([datetime],[_date],(11))),
[Audit_Trail] [varchar](20) NULL,
CONSTRAINT [PK_AmtoteAccountActivity2] PRIMARY KEY NONCLUSTERED
(
[RecordID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
(Clustered Index)
USE [EWS]
GO
/****** Object: Index [IX_AmtoteAccountActivity2] Script Date: 02/17/2017 21:06:29 ******/
CREATE CLUSTERED INDEX [IX_AmtoteAccountActivity2] ON [dbo].[AmtoteAccountActivity]
(
[AccountNumber] ASC,
[_Date] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
( Hinweis: Für alle, die sich fragen, warum anscheinend finanzielle und numerische Werte in Zeichenfeldern gespeichert sind: Das war das ursprüngliche Tabellendesign vor 17 Jahren (nicht von mir), und es gibt jetzt Hunderte von SQL-Abfragen, die in dieser Datenbank ausgeführt werden arbeiten Sie daran, sie als varchar zu behalten, und die Abfragen behalten ihr Casting bei, als sie in Geld, int oder dezimal umzuwandeln und Hunderte von Abfragen zu ändern.
quelle
NULL
oder definiertNOT NULL
?Antworten:
Erstellen wir drei Tabellen mit einer varchar-Spalte, von denen zwei NULL zulassen, eine nicht.
Füllen Sie sie mit 1.000.000 Zeilen:
Lassen Sie uns die Größe überprüfen:
Ergebnisse:
So ist es wie für 1.000.000 Zeilen sieht, die Wahl
NULL
über''
spart ein sattes 8 KB (und dies spiegelt sich nicht einmal insp_spaceused
, denn das ist eine Seite , die Sie noch reserviert gespeichert wird, nur nicht zugeordnet).Wiederholt für einen Heap (müssen erneut mehrere Tests durchführen, da wir über Ihre tatsächliche Tabellenstruktur raten):
Wie ich bereits angedeutet habe und sogar 120.000.000 Zeilen extrapoliert, wäre der größtmögliche Unterschied (je nach Schema noch einmal) 960 KB in einer richtigen Tabelle und 6,7 MB in einem Heap. Wenn auf Ihrem Server so wenig Speicherplatz zur Verfügung steht, dass 6,7 MB Entscheidungen treffen, können Sie überlegen, wie viel eine zusätzliche Festplatte im Vergleich zu der Zeit, die Sie für die Untersuchung dieses Speicherplatzes benötigen, kosten würde.
Meiner Meinung nach gibt es weitaus wichtigere Gründe zwischen der Entscheidung, NULL-Werte zu verwenden oder nicht "keine Daten" darzustellen. Eine gute Frage mit vielen Meinungen und Kommentaren ist hier:
quelle
In diesem Artikel wird erläutert, wie SQL NULL-Werte speichert .
Grundsätzlich speichert eine Spalte mit variabler Breite (varchar) eine Bitmap, die null oder nicht null angibt. Wenn es null ist, werden dem varchar-Feld null Bytes zugewiesen und das Bit wird umgedreht.
Bei Spalten mit fester Breite (char) wird weiterhin das gesamte Feld zugewiesen, ohne dass Daten darin gespeichert sind. Ein 10-Yte-Zeichenfeld weist also 10 Bytes zu, NULL oder nicht.
Dieser Artikel führt eine Einfügung mit Daten, mit NULL und mit leerer Zeichenfolge durch. Anschließend wird die Seitengröße abgefragt, um festzustellen, was intern vor sich geht.
Sowohl für Null- als auch für leere Zeichenfolgen werden 0 Bytes für Varchar-Felder zugewiesen.
quelle
Zumindest für das Standarddatensatzformat ( FixedVar ) spielt es keine Rolle , wie viel Speicherplatz die Tabelle belegt (dies kann einen geringfügigen Unterschied zu den Indizes bewirken, wie später erläutert wird).
Sowohl eine Null-
varchar
als auch eine leere Zeichenfolge werden genauso gespeichert. Sie können nur unterschieden werden, ob eine1
oder eine0
Null-Bitmap vorhanden war. Beide nehmen im Abschnitt mit den Spaltendaten variabler Länge die Länge Null an, und beide können auch vermeiden, zwei Bytes im Array mit variablem Spaltenversatz zu belegen, wenn ihnen keine Spalten folgen, die Daten enthalten.Einer der Kommentare sagt
Dies gilt nicht für Datenseiten. Siehe Mythos Nr. 6b: Die Null-Bitmap enthält nur Bits für nullfähige Spalten .
Bei Indizes besteht ein geringfügiger Unterschied darin, dass die Null-Bitmap weggelassen wird , wenn nicht alle an einem Index beteiligten Spalten nullwertfähig sind.
Der Unterschied ist jedoch vernachlässigbar und Sie sollten die Option auswählen, die Ihnen die gewünschte Semantik bietet.
quelle