2011-05-17 80 views
2

想象一下,我們有一組實體,每個實體都有其狀態:空閒,忙或破碎。狀態被指定爲一天,例如,今天在2011-05-17,一個實體E1是免費的,明天在2011年5月18日它很忙。將以下時態數據存儲在數據庫中的最佳方式

需要在1000天內存儲〜10^5個實體。哪種方法是最好的方法?

我想2個選擇:

  • 代表每一天都當作一個字符「0」,「1」或「2」,並存儲爲每一個實體的每一天1000個字
  • 店字符串與實體的狀態連續,即對於實體的1000行

對於這樣的數據最重要的查詢是:給定的開始日期和結束日期標識哪些實體是空閒的。

性能的優先級高於存儲。

歡迎提出任何建議和意見。

+0

如果實體是在天10和12免費的,但不是在第11天 - 它應該被認爲是「第10和12之間的自由」? – tucuxi 2011-05-17 13:18:47

+0

它必須明確定義,即如果它在第10天和第12天是空閒的,那麼我們對第11天一無所知。然而,如果存儲時間片段,那麼它可以如此定義:[10,12]是免費的。但我覺得這種方式更復雜。 – Tim 2011-05-17 13:22:59

回答

2

創建一個表來保存您的數據。使用ID,日期,實體名稱和八個布爾字段創建表格。 SQL Server 2008給了我下表的代碼:

CREATE TABLE [dbo].[EntityAvailability](
[EA_Id] [int] IDENTITY(1,1) NOT NULL, 
[EA_Date] [date] NOT NULL, 
[EA_Entity] [nchar](10) NOT NULL, 
[EA_IsAvailable] [bit] NOT NULL, 
[EA_IsUnAvailable] [bit] NOT NULL, 
[EA_IsBroken] [bit] NOT NULL, 
[EA_IsLost] [bit] NOT NULL, 
[EA_IsSpare1] [bit] NOT NULL, 
[EA_IsSpare2] [bit] NOT NULL, 
[EA_IsSpare3] [bit] NOT NULL, 
[EA_IsActive] [bit] NOT NULL, 
CONSTRAINT [IX_EntityAvailability_Id] UNIQUE NONCLUSTERED 
(
    [EA_Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
END 
GO 

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[EntityAvailability]') AND name = N'IXC_EntityAvailability_Date') 
CREATE CLUSTERED INDEX [IXC_EntityAvailability_Date] ON [dbo].[EntityAvailability] 
(
    [EA_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] 
GO 

日期聚集索引將執行最適合您的範圍搜索。永遠不允許沒有日期範圍的搜索,並且除了聚集索引之外不需要任何索引。布爾字段允許只使用一個字節的八種情況。該表的行大小爲35個字節。 230行將適合頁面。您表示您需要存儲1000個日期的10^5個實體,即1億個。一億行將佔用434,782 8K頁或約3演出。

SSD上安裝表,你可以走了。

1

取決於實體是否更經常是免費的,只是存儲實體免費或不實際的日期。

假設你存儲的日期時,該實體是不自由,則搜索是從哪裏開始日期< =日期日期和結束日期> =日期和任何行匹配,這意味着該實體是不自由的那一段

+0

好吧,實體可能會在未來有超過2個的狀態,例如,免費的,忙壞 – Tim 2011-05-17 13:03:54

+0

如果只有3然後爲每個忙碌的一個表,並打破 - 否則添加標記爲忙碌,破碎等日期表 – Mark 2011-05-17 13:19:03

0

它聽起來你可能會走在正確的軌道上,我會建議,因爲記錄的數量和性能的重點,你保持架構儘可能非規範化。爲了確定空閒或繁忙實體,您需要做的聯接越少越好。

+0

在這種情況下,連接可能與使用替代ID號碼有關,而不是歸一化。儘管如此,不要使用代理ID號作爲州使用CHAR(1)和'F','B'和'X'「將是很好的建議。 – 2011-05-17 21:48:39

3

最好的方法是首先嚐試更簡單和更靈活的選項(即將每天存儲在自己的行中),並且只在性能不理想時才設計出複雜的替代方法。避免過早優化。

10^8行對於目前商品服務器上的普通數據庫並不是什麼大不了的事情。把一個索引放在日期上,我敢打賭,範圍查詢(「給定開始日期和結束日期...」)將工作得很好。

的原因,我聲稱,這既是簡單,不是存儲1000個字符的字符串的想法更加靈活的有:

  • 你必須在代碼來處理這一點,該代碼不會這很容易理解爲查詢包含日期和狀態的DB記錄的代碼。
  • 根據數據庫引擎的不同,1000個字符串可能是存儲在記錄外部的斑點。這使得他們效率較低。
  • 如果您突然需要2,000天而不是1,000天會發生什麼?開始更新所有行和處理它們的代碼?這不僅僅是改變你的查詢。
  • 當您接下來要求每日記錄存儲一些附加信息或需要更改粒度時(例如從幾天移動到幾小時)會發生什麼?
+3

同意 - 對索引列執行範圍查詢要比對計算數組逐一屏蔽10萬個實體要快得多。不太緊湊的存儲方式,但速度更快。我假設這個EntityStatus表只包含一個entity-id,一個日期和一個狀態(free,broken,whatever)。 – tucuxi 2011-05-17 13:32:58

0

我會廣泛去尋找一個Kimball Star Schema(http://en.wikipedia。組織/維基/ Star_schema)配有三個表(初始)

  • FactEntity(FK kStatus,kDate)
  • DimStatus(PK kStatus)
  • DimDate(PK kDate)

這種類型的結構可以非常簡單地加載(Dims first,然後是Fact(s)),並且查詢也很簡單。性能可以通過適當的索引進行優化。

這種設計的一大優勢是,它是非常可擴展;如果你想增加日期範圍,或者增加有效狀態的數量,那麼擴展是微不足道的。

其他尺寸可以合理地加入,例如, DimEntity可以有更豐富的信息,可以給出分類信息,遷移有趣的切片/切塊你的實體。

DimDate通常通過添加DayNo,MonthNo,YearNo,DayOfWeek,WeekendFlag,WeekdayFlag,PublicHolidayFlag來豐富。這些允許進行一些非常有趣的分析。

由於@Elad問,如果添加基於時間的信息會有什麼ahppen,那麼這也可以通過在每個小時或分鐘一個記錄一個DimTime尺寸inforporated。

道歉我命名,因爲我沒有你的數據有很好的理解。考慮到更多的時間,我可以拿出一些更好的!

0

enter image description here

要獲得一個約會免費的實體,您可以嘗試:

select 
     e.EntityName 
    , s.StateName 
    , x.ValidFrom 
from EntityState as x 
join Entity  as e on e.EntityId = x.EntityId 
join State  as s on s.StateID = x.StateID 
where StateName = 'free' 
    and x.ValidFrom = (select max(z.ValidFrom) 
         from EntityState as z 
         where z.EntityID = x.EntityID 
         and z.ValidFrom <= your_date_here) 
; 

注意:請確保您存儲在EntityState表只是狀態的變化。

相關問題