2009-08-31 23 views
6

我有2個文件,我想導入到MS SQL中。第一個文件是2.2 GB,第二個文件是24 GB的數據。 (如果你很好奇:這是一個撲克相關的查找表)非常巨大的SQL數據庫:模式應該如何?

將它們導入MS SQL不是問題。感謝SqlBulkCopy,我能夠在短短10分鐘內導入第一個文件。我的問題是,我不知道實際的表模式應該如何讓我做一些非常快的查詢。我第一次嘗試天真看起來是這樣的:

CREATE TABLE [dbo].[tblFlopHands](
    [hand_id] [int] IDENTITY(1,1) NOT NULL, 
    [flop_index] [smallint] NULL, 
    [hand_index] [smallint] NULL, 
    [hs1] [real] NULL, 
    [ppot1] [real] NULL, 
    [hs2] [real] NULL, 
    [ppot2] [real] NULL, 
    [hs3] [real] NULL, 
    [ppot3] [real] NULL, 
    [hs4] [real] NULL, 
    [ppot4] [real] NULL, 
    [hs5] [real] NULL, 
    [ppot5] [real] NULL, 
    [hs6] [real] NULL, 
    [ppot6] [real] NULL, 
    [hs7] [real] NULL, 
    [ppot7] [real] NULL, 
    [hs8] [real] NULL, 
    [ppot8] [real] NULL, 
    [hs9] [real] NULL, 
    [ppot9] [real] NULL, 
CONSTRAINT [PK_tblFlopHands] PRIMARY KEY CLUSTERED 
(
    [hand_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]

動態指數是從1到22100的值(前3張常見的德州撲克卡,52選3)。每個觸發器索引都有一個從1到1176的hand_index(49選擇2)。所以總共有25,989,600行在這張表中。

用我上面的「模式」做一個查詢需要約。 25秒。經過一些Google搜索後,我發現SQL服務器正在進行表掃描,這顯然是一件壞事。我運行了「數據庫引擎優化顧問」,並建議在flop_index列上創建一個索引(合理)。創建索引後,DB所需的磁盤空間增加了一倍! (加上日誌LDF文件增長了2.6 GB) 但是在索引之後,查詢只花了幾個毫秒。

現在我的問題是,我該如何正確地做到這一點?我從來沒有用過這麼龐大的數據,我之前創建的數據庫只是一個笑話。

需要注意的一些事項:將數據導入MS SQL後,永遠不會插入或更新數據,只需選擇即可。所以我想知道我是否需要主鍵?

編輯:我提供一些更多的信息,使我的問題更加清晰:

1)我將永遠不會使用hand_id。我只是把它放在那裏,因爲很久以前有人告訴我,我應該總是爲每個表創建一個主鍵。

2)將基本只有一個查詢,我將使用:

SELECT hand_index, hs1, ppot1, hs2, ppot2, hs3, ppot3, hs4, ppot4, hs5, ppot5, hs6, ppot6, hs7, ppot7, hs8, ppot8, hs9, ppot9 WHERE flop_index = 1...22100

此查詢將始終與我所需要的數據返回1176行。

編輯2:只是更具體:是的,這是靜態數據。我有這個數據在一個二進制文件。我已經編寫了一個程序來在幾毫秒內用我需要的數據查詢這個文件。我想在數據庫中使用這些數據的原因是,我希望能夠從網絡中的不同計算機查詢數據,而無需在每臺計算機上覆制25 GB的數據。

HS表示手牌強度,它會告訴你當前手牌與翻牌或轉牌相結合的手牌強度。 ppot意味着積極的潛力,這是一旦下一張普通卡被處理,你的手就會處於領先地位的機會。 hs1到9是對抗1到9個對手的手牌。同一個ppot。實時計算ppot非常密集,需要幾分鐘才能計算。我想創建一個撲克分析程序,該程序給出了在任何翻牌圈/轉牌圈的每個可能的底牌組合以及他們的hs/ppot。

+5

只是爲了將來的參考,這是一個小型SQL數據庫,而不是一個巨大的;) – 2009-08-31 19:43:20

+2

嗯,它是*不*小。但無論如何,說數據庫真的很大是主觀的。有很多更大的數據庫的例子。只要說出幾千兆字節就可以了。 – 2009-08-31 19:45:00

+0

好吧,它可能不是一個巨大的谷歌數據庫或類似,但對於一個寵物項目,我認爲它是相當巨大的:) – Simon 2009-08-31 19:46:56

回答

0

這是一個很常見的問題。創建索引時,可能會縮短查詢所需的時間,但會增加更新/插入所需的時間,並且還會增加每條記錄所需的磁盤空間量。

如果索引爲查詢提供了性能提升,並且它確保影響插入/更新性能和磁盤空間利用率,則需要爲每列確定一次。

作爲索引的替代方法,您可能可以使用OLAP cube。如果您的查詢正在生成聚合或應用計算,那麼您可能需要考慮每晚執行查詢並將結果存儲在其他表中。您可以針對較小的表運行更簡單的查詢,並獲得相同的結果,同時對性能影響較小。

0

你如何做你的索引和primkeys取決於。如果你只是想分析數據,並且你確信後續的DML命令只會是SELECT(不插入),那麼刪除PK應該沒問題。實際上,hand_id列是一個IDENTITY(自動增量)列,這意味着SQL Server無論如何都管理該值(事實上,如果不在之前切換到IDENTITY_INSERT模式的額外麻煩中,則無法將值插入該列中開始你的INSERT語句,IIRC)。

當然,請謹慎對待這個數據庫的不斷變化的需求。如果需要改變,那麼你應該考慮約束/索引/鍵。

如果將來要考慮數據挖掘,請考慮使用Microsoft的SSAS(分析服務)。更新:在閱讀mayo的回覆之後,我同意索引(純粹是爲了速度,而不是約束實施)對於後續查詢是可取的(回想起索引加速讀取操作但通常使插入/更新花費更長時間)。由於您的目標是執行一個批量插入,然後執行SELECT查詢,因此您可以進行批量插入,然後將可能候選人的查詢中所需的索引添加到數據庫中。

+0

其實我根本不會使用hand_id。我創造了PK,因爲我被教導要在每張桌子上總是創造一個PK。另外,在我的場景中,插入數據後永遠不會有任何插入或更新。此外,我會一直使用hand_index查詢,因此每個查詢將返回1176行。那麼在hand_index列上創建索引後,數據庫大小加倍後,這是否正常?我認爲這很奇怪,但如果它像這樣工作,那就讓它成爲它吧。 – Simon 2009-08-31 19:57:49

1

要回答你的問題有關需要一個主鍵 - 只有你在問題中所提供的信息:

根據您的表模式,你還不如把它那裏。如果你刪除了這個標識列,你也會刪除你的聚集索引。您的聚簇索引值(4個字節)作爲指針存儲在每個非聚簇索引行中。通過刪除聚集索引,你可以將表格作爲一個堆 - SQL將爲表中的每一行創建一個8字節的RID(行標識符),並將其用作非聚集索引中的指針。所以,就你而言,根據你在問題中提供的模式 - 你可能會增加非聚集索引的大小,並最終減慢它們的速度。

由於所有的說 - 基於您可能正在運行的查詢(及其使用模式)未包含在問題中 - 評估您的聚簇索引是標識列以外的內容可能與好。

1

那麼,如果例如hs(X)和ppot(X)需要增長到九點以上,那麼你可以將表格拆分成較小的表格。

這是你擁有的一切:

[hand_id] [int] IDENTITY(1,1) NOT NULL, 
    [flop_index] [smallint] NULL, 
    [hand_index] [smallint] NULL, 
    [hs1] [real] NULL, 
    [ppot1] [real] NULL, 
    etc... 

你可以把它分解成2個表(也許3如果需要)

Table hand: (EXAMPLE) 
[hand_id] [int] IDENTITY(1,1) NOT NULL, 
    [flop_index] [smallint] NULL, 
    [hand_index] [smallint] NULL 


Table hs_ppot (EXAMPLE) 
[hand_id] [int] IDENTITY(1,1) NOT NULL, 
[hs] [real] NULL, 
    [ppot] [real] NULL 

然後,你可以在每個表由hand_id引用。只是一個雖然。

BTW什麼是hs和ppot?

+0

hs意味着Handstrength和ppot的意思是「積極的潛力」 – Simon 2009-08-31 20:12:00

+0

好的謝謝,沒有大的撲克 – 2009-08-31 20:23:30

+0

我實際上試圖將數據分成多個表格,我會讓你知道它是如何工作的。不幸的是,我並不擅長SQL;) – Simon 2009-08-31 20:36:56

0

讓我先說一下我的迴應,說把每一種可能的組合都放在數據庫中感覺不對。我會在一分鐘後回答爲什麼。

我會從名爲卡片的桌子開始。每個可能的卡片將有1條記錄,並且它將包括適合套牌,面值,等級和是的字段,CardID作爲主要關鍵字。也索引訴訟,並面值。

如果你想列出每一個可能的德州撲克牌,那麼我會爲pocketCards(pocketID,pCardID1,pCardID2),flopCards(flopID,fCardID1,fCardID2,fCardID3)製作單獨的表格,然後爲TurnAndRiver (turnAndRiverID,turnCardID,riverCardID)。然後一個手錶(handID,pocketID,flopID,turnAndRiverID,handScore)。

HandScore將是一個計算字段從表或標量值函數運行。

通過分離出這些位,可以避免大量的重複,但您仍然需要擔心卡的選擇和重疊。

理想情況下,我會放棄手錶並計算手和得分的數據。

當您的客戶要求您建模奧馬哈或五張牌時,將過多的邏輯放在數據庫中可能會使其很難適應。

對於您的索引問題,是的,我會使用主鍵,因爲這可以讓您快速引用代碼中的特定手。

更新

爲響應OP的編輯:這聽起來像你正在使用該任務的錯誤的工具。如果您總是選擇完全相同的記錄集,那麼在數據庫中擁有數據的價值是什麼?檢查其他選項(例如,平面XML文件或代碼中的靜態DataSet)。它將爲您節省連接時間和爲本質上靜態數據運行服務器的開銷。