2012-03-19 25 views
0

我有一個超過300萬行(我的用戶信息)的龐大數據庫,我需要選擇當天有生日的所有用戶。什麼是從一個巨大的數據庫中選擇行的最快方法?

生日列是text(例如'19/03' 或'19/03/1975' )與日和月,有時年。

當我試着用左側的功能,如它需要更多的則一分鐘,返回的結果來選擇行。

我試過使用3 int列daymonthyear,然後做出選擇,但它需要更長的時間才能得到結果。

如何使其運行速度更快的任何想法?

我使用SQL Server 2008

感謝

+7

首先:如果它是**日期** - **將它作爲「日期」存儲!通過這種方式,您可以隨時保存所有的轉換數據......第二:如果您需要快速搜索,請在該列上放置一個**索引**(並可能包含更多列以滿足您的查詢) 。第三:3百萬行是**甚至不接近巨大** - 這是一箇中等大小的表格 - 最多..... – 2012-03-19 08:44:34

+1

當您使用三個整數時,您是否索引這些列? – 2012-03-19 08:45:27

+0

我有,我正在說話。但我們不要爭論蒂姆。 – deed02392 2012-03-19 08:57:59

回答

1

首先是保存在由SQL Server類似DATEDATETIME支持的格式的日期(以你的情況我猜DATE應足夠了),一旦你有,你可以使用SQL的功能,如MONTHDAY如下,並避免類似LEFT等

您的查詢將看起來像這樣複雜的字符串處理函數:

select * from MyTable where MONTH(dateColumnA) = '1' && DAY(dateColumnB) ='7' --1 is for january 

我不確定這是否會完全解決您的性能問題,但您可以在SQL查詢分析器中運行此查詢,並查看針對索引等提出的建議。我沒有關於索引的大量知識on日期類型列

+1

爲了準確, - (而不是//)是SQL中的註釋 – 2012-03-19 08:51:31

+1

這是第一步 - 使用**正確的數據類型**。第二步是**索引**欄加快搜索速度 – 2012-03-19 08:52:14

+0

@ElJay哈哈!我的手只是伸出手//當我要評論時,不管語言如何。:D – Baz1nga 2012-03-19 08:54:00

2

由於marc_s提及,如果可能的話,將其作爲日期類型存儲 - 它將使SQL Server執行比較的速度更快,而且維護起來會更容易。接下來,請確保在該列上放置索引,並考慮包括任何額外的列,如果您只查找生日以選擇總行的一小部分。

最後 - 這是一個很大的。 TEXT只是您可以選擇的最差的數據類型。 TEXT存儲的方式,數據實際上並不存儲在頁面上。相反,它會留下指向另一頁的16字節指針。然後這個其他頁面將數據本身包含在記錄中。但情況會變得更糟,那麼當您的數據長度在0到64個字節之間時,該記錄將是一個SMALL_ROOT數據類型,佔用84個字節的空間!

因此,有什麼能一直保存爲8字節datetime或4個字節的日期現在佔用共有100個字節,並導致斷行查找的每一個行。基本上是對糟糕表現的完美風暴。

如果你不能將其更改爲更合適的日期時間,至少是,將其更改爲varchar!

0

大多數的什麼,我不得不說已經說過的話:使用DATE類型存儲日期,並確保它被索引。如果你要使用三個整數存儲日期和通過搜索,然後確保他們索引以及:

CREATE INDEX IX_MyTable_Date_Ints ON MyTable(intYear, intMonth, intDay) 
CREATE INDEX IX_MyTable_Date ON MyTable(BirthDate) 

如果你想能夠搜索用戶表對於不包括年份的生日,我建議使用固定的年份將生日存儲在不同的日期字段中,例如3004 - 而不是使用三個整數。你的基年應該是一個閏年,以迎合2月29日出生的任何人。如果你在將來使用一年,你可以使用年份來確定一個日期實際上是一年不應該被忽略的日期。

然後,您可以搜索生日,無論年份如何,無需在每條記錄上進行函數調用,只需添加「WHERE birth_day ='3004-12-10'。如果此字段已編入索引,則應該能夠在閃存中返回所有匹配的行,需要記住的是,當搜索一個索引時,服務器需要做最多32次比較才能找到匹配的40億條記錄。

我會傾向於通過一個觸發器來維持生日,這樣它就會保持自己的更新。對於那些沒有年份的出生日期,只需使用基準年(3004)。由於基準年在未來,你知道這個出生日期沒有一年。

CREATE TABLE MyTable (
    MyTable_key INT IDENTITY(1, 1), 
    username VARCHAR(30), 
    birth_date DATE, 
    birth_day DATE 
) 
ALTER TABLE MyTable ADD CONSTRAINT PK_MyTable PRIMARY KEY CLUSTERED (MyTable_key) 
CREATE INDEX MyTable_birth_date ON MyTable(birth_date) 
CREATE INDEX MyTable_birth_day ON MyTable(birth_day) 
GO 
CREATE TRIGGER tr_MyTable_calc_birth_day ON MyTable AFTER INSERT, UPDATE AS 
    UPDATE t SET birth_day = DATEADD(YEAR, 3004-DATEPART(YEAR, t.birth_date), t.birth_date) 
    FROM MyTable t, inserted i WHERE i.MyTable_key = t.MyTable_key 

要更新現有的表,運行更新作爲一個獨立的查詢,沒有因爲它是在觸發用於聯接到inserted表:

UPDATE MyTable SET birth_day = DATEADD(YEAR, 3004-DATEPART(YEAR, birth_date), birth_date) 

希望這有助於。

0

嘗試使用結果集而不是DataTable或DataSet。結果集比這兩個都快。

相關問題