只有一個常數值的表?
我首先使用 C# 實體框架程式碼。
我對數據庫的了解幾乎一無所有。我不知道這是常見的還是好的做法,所以我想問你們我應該怎麼做。
假設我有一張字母表和一張電台表。
我開發了一個應用程序,可以將信件從一個站點發送到其他站點。每封信都可以發送到不同的站點——這是多對多的關係。
發送的每封信都與一個站相關聯 - 信的源站(一封信不能發送到它自己的源站等)。
每個數據庫實例代表一個站。
在應用程序啟動時,我知道哪個站是我的源站,並希望將該資訊保存在數據庫中。
我應該如何保存哪個站是源站?我是否應該在每一行的站表中都有一個標誌,指示它是否是目前實例站?這對我來說聽起來很糟糕。
有沒有辦法讓一張只有 1 個值的表?例如,這將被稱為 InstanceStation,它將僅包含一行和一列 - StationId?這是一個好習慣嗎?
我試圖盡可能清楚,我希望我的情況很清楚。
假設您沒有十億個站點,那麼在
Stations
桌子上放置一個指示哪個站點是本地站點的標誌正是我處理此問題的方式。我可能會呼叫該列IsSourceStation
或其他東西,並使其成為一個BIT
可以接受的值NULL
。我會將本地站行標記為1
,並將所有其他行保留為NULL
,因為這不會佔用任何空間(請參閱下面關於空間的評論)。我會在
IsSourceStation
列中添加一個過濾索引,過濾為WHERE IsSourceStation = 1
. 如果需要,該索引將允許極快的查找來確定本地電台的名稱。尋找
Stations
與我們的“家”站相對應的行可以通過以下方式完成:SELECT * FROM Stations WHERE IsSourceStation = 1;
無論表中有多少行,我建議的索引都會非常快
Stations
。想要確認一個電台不是主電台?用這個:
IF EXISTS ( SELECT 1 FROM Stations WHERE IsSourceStation IS NULL AND StationID = 1234 ) BEGIN -- StationID 1234 is NOT the home station END
SQL Server 中使用的空點陣圖是一種出色的優化,專為這種情況而設計,可空列中只有很少的行實際上包含值。
我上面的陳述雖然在技術上是正確的,因為空點陣圖用於節省空間,但在具有單個位列的表的情況下,將列定義為可為空與使其不可為空之間沒有明顯區別預設值為 0。我在 SQL Server 2012 上使用以下測試台來確定這一點:
USE tempdb; IF EXISTS (SELECT 1 FROM sys.tables t WHERE t.name = 'TestBit') DROP TABLE dbo.TestBit; IF EXISTS (SELECT 1 FROM sys.tables t WHERE t.name = 'TestBitNotNull') DROP TABLE dbo.TestBitNotNull; CREATE TABLE dbo.TestBit ( TestBitID INT NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1,1) , IsBit BIT NULL ); INSERT INTO dbo.TestBit (IsBit) SELECT TOP(1000000) NULL FROM sys.objects o1 , sys.objects o2 , sys.objects o3 , sys.objects o4; CREATE TABLE dbo.TestBitNotNull ( TestBitID INT NOT NULL PRIMARY KEY CLUSTERED IDENTITY(1,1) , IsBit BIT NOT NULL CONSTRAINT DF_TestBitNotNull DEFAULT ((0)) ); INSERT INTO dbo.TestBitNotNull(IsBit) SELECT TOP(1000000) 0 FROM sys.objects o1 , sys.objects o2 , sys.objects o3 , sys.objects o4;
上面的程式碼創建了兩個表,每個表都有一個
INT
列和一個BIT
列。第一個表允許BIT
列是NULL
; 第二個表沒有。我使用以下內容檢查每個表第一頁的實際磁碟數據頁:
SELECT TOP(10) * , %%PHYSLOC%% FROM dbo.TestBit CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%); SELECT TOP(10) * , %%PHYSLOC%% FROM dbo.TestBitNotNull CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%);
該
DBCC PAGE
命令可以與設置為“3”的最後一個選項一起使用,以查看儲存在頁面上的實際列值,以及每行“槽”的相當多的細節。在我上面的兩個表中,每個表的第一頁分別是 334 和 342。DBCC PAGE (2, 1, 334, 3) WITH TABLERESULTS; DBCC PAGE (2, 1, 342, 3) WITH TABLERESULTS;
上面每個 DBCC PAGE 命令的插槽 0 的輸出顯示了具有可為空列的表的以下內容:
這對於不可為空的列:
第一行第 2 列的“記憶體轉儲”值以十六進制格式顯示儲存在磁碟上的實際數據;兩種變體完全相同。
實際上,當使用此查詢查看兩個表的磁碟大小時:
SELECT o.name , i.name , p.partition_number , p.rows , UsedMB = au.used_pages / 8192E0 , TotalMB = au.total_pages / 8192E0 , AvgRowsPerPage = p.rows / CONVERT(DECIMAL(10,2), au.used_pages) FROM sys.allocation_units au WITH (NOLOCK) INNER JOIN sys.partitions p WITH (NOLOCK) ON ((au.type = 1 OR au.type = 3) AND au.container_id = p.hobt_id) OR (au.type = 2 AND au.container_id = p.partition_id) INNER JOIN sys.indexes i ON p.object_id = i.object_id AND p.index_id = i.index_id INNER JOIN sys.objects o WITH (NOLOCK) ON p.object_id = o.object_id INNER JOIN sys.schemas s WITH (NOLOCK) ON o.schema_id = s.schema_id WHERE o.name = 'TestBit' OR o.name = 'TestBitNotNull' ORDER BY o.name;
我們看到兩個表的大小相同:
根據上述數據,我的結論是,僅使用預設值為 0 的不可空列可能更容易,因為這消除了可空列所需的潛在問題空處理。
當您有超過 8 個可空位欄位時,空點陣圖*確實有幫助。*如果您使用我的範例表
TestBit
並TestBitNotNull
給它們每個 16 位欄位,您將看到以下 1,000,000 行的表大小: