2012-09-14 35 views
0

我有一個SQLServer表與我的不同類型的查詢通常的說明在指數上的日期時間字段,其中包括列

intID(primary key),field1,field2,manyotherfields..., datetime TimeOperation

99%,開始與TimeOperation BETWEEN startTime AND endTime,然後select * (or count(*)) where fieldA=xxx,並與加盟其他較小的桌子。 select *因爲或多或少我需要所有的領域。

我明確地在TimeOperation上創建了一個索引......但是性能不夠好,所以我想添加一些索引鍵列或索引包含的列,但我有點困惑。

我得到了兩者之間的差異,但我不明白在每種情況下添加列會對速度和尺寸產生多大的影響。

我想最大的改進是創建一個包含所有列的索引,是不是? (但我買不起空間)

而且,如果我經常使用field1=xxx例如,將field1添加到索引鍵列(在TimeOperation之後)會有更好的表現嗎?

另外...只是爲了確保包含列的索引是如何工作的:如果我在某一範圍內選擇TimeOperation的行,sql會爲我感興趣的行尋找我的TimeOperation索引,並且它比掃描所有的表格,因爲在索引中TimeOperation值是按升序排列的,對嗎?但後來我需要所有數據,現在我需要這些行的所有其他數據字段...... sql如何檢索數據?我想它對索引中的那些行有一種書籤,對吧?但它必須多次擊中表格...所以包括索引中的所有列將節省時間來擊中表格,它是否正確?

謝謝! 馬蒂亞

+2

「'select *'因爲或多或少我需要所有的字段。」這不是一個很有說服力的理由。想象一下,如果其中一列是「varchar(max)」,其中每行存儲1GB文檔。如果你沒有*使用那個欄目,那麼很多浪費資源來檢索它們。即使目前情況不是這樣,如果這樣的一列在6個月後被添加了,該怎麼辦?突然間,所有人「'select *'因爲我需要大多數列」查詢變得非常慢。 –

+0

SELECT *很懶。請閱讀這篇文章,其中包括一個解決方法,無需執行所有耗時的指關節式打字工作(只刪除不需要的列):http://sqlblog.com/blogs/aaron_bertrand/archive/2009 /10/10/bad-habits-to-kick-using-select-omitting-the-column-list.aspx –

+0

對不起,我表達得很糟糕,我並不是說我使用「select *」,我只提取了我需要在不同的查詢中使用列。我的意思是,在每個查詢中,我使用日期時間範圍,並考慮所有查詢,我請求所有列......我的意思是:對於性能解決方案,我需要專注於如何更好地排序日期時間 –

回答

1

我們需要您的查詢的表格示例的詳細信息,以充分解決這個問題,但是:

  • 日期時間列應自行高度選擇性,因此與TimeOperation指數作爲第一列應解決針對TimeOperation的大部分查詢。
  • 不要盲目地將所有列添加到索引或甚至包含索引 - 這會使索引頁面密度變差併產生反效果(您將在索引中複製表)。
  • 如果數據庫中的所有數據都以TimeOperation爲中心,那麼可以考慮圍繞它構建聚簇索引。
  • 如果您只對field1 = x有疑問,那麼您需要一個單獨的索引,僅用於field1(假設它具有適當的選擇性),即索引上不存在TimeOperation(如果它不在查詢的WHERE子句中)。
  • 是的,當然,當SQL在索引中查找記錄時,它需要執行一個鍵(或RID)lookup back into the cluster來檢索其餘列。如果您的非聚集索引包含select語句中的其他列,則可以避免查找。但由於您使用的是SELECT(*),因此覆蓋索引不太可能有所幫助。

編輯

解釋 - 選擇性和密度進行詳細here說明。例如如果針對TimeOperation的查詢僅返回少量行(經驗法則爲< 5%,但並非總是如此),那麼索引是否會被使用,即您的查詢是否具有選擇性,足以讓SQL選擇TimeOperation上的索引。

的基本出發點是:

CREATE TABLE [MyTable] 
(
    intID INT ID identity(1,1) NOT NULL, 
    field1 NVARCHAR(20), 
    -- .. More columns, which may be selected, but not filtered 
    TimeOperation DateTime, 

    CONSTRAINT PK_MyTable PRIMARY KEY (IntId) 
); 

的基本指標進行

CREATE NONCLUSTERED INDEX IX_MyTable_1 ON [MyTable](TimeOperation); 
CREATE NONCLUSTERED INDEX IX_MyTable_2 ON [MyTable](Field1); 

聚類審議/選項

如果大部分的記錄插入以'串行'升序的TimeOperation順序,即intId和TimeOpe配給量將同時增加,那麼我將離開intID(默認值)(即,表DDL是PRIMARY KEY CLUSTERED (IntId),這是默認情況下)。

但是,如果有NOIntIdTimeOperation,並且IF大部分的查詢的形式是SELECT * FROM [MyTable] WHERE TimeOperation between xx and yy然後CREATE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)(和不斷變化的PK到PRIMARY KEY NONCLUSTERED (IntId))應改善查詢(基本原理之間的相關性:因爲連續次保持在一起,需要讀取更少的頁面,並且書籤查找將被避免)。更好的是,如果TimeOperation的值保證是唯一的,那麼CREATE UNIQUE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)將提高密度,因爲它將避免唯一性。

- 對於這個答案的其餘部分,我假設你IntIdTimeOperations是強相關的,因此集羣是由IntId

覆蓋索引

正如其他人所說,你的SELECT (*)使用是不好的做法和尤其手段覆蓋索引將不會有任何使用(唯一的例外是COUNT(*))的。 如果您的查詢不是SELECT(*),而是例如

SELECT TimeOperation, field1 
FROM 
WHERE TimeOperation BETWEEN x and y -- and returns < 5% data. 

然後改變上TimeOperation索引以包括field1

CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation) INCLUDE(Field1); 

OR同時添加到索引(第一,最常見的過濾器,或最有選擇性的第一,如果兩個濾波器總是存在)

CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation, Field1); 

要麼會避免rid/key查找。第二個(,)選項將解決您的查詢,其中BOTH TimeOperation和Field1在WHERE或HAVING子句中被過濾。

回覆:索引(TimeOperation,Field1)和單獨索引之間有什麼區別?

例如

CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation, Field1); 

不會對查詢有用

SELECT ... FROM MyTable WHERE Field1 = 'xyz'; 

該指數將只針對有TimeOperation

SELECT ... FROM MyTable WHERE TimeOperation between x and y; 

OR

SELECT ... FROM MyTable WHERE TimeOperation between x and y AND Field1 = 'xyz'; 

希望這個查詢有用幫助?

+0

您能否詳細說明「DateTime專欄應該是非常有選擇性的」,我不明白你的意思。 如果我在Where子句中使用TimeOperation和field1進行查詢,那麼擁有TimeOperation索引和field1索引以及具有單個TimeOperation和field1索引的區別是什麼? 謝謝! –

+0

@MattiaDurli我在回答中添加了說明。 – StuartLC

+1

是的,擴展的答案澄清了很多事情。 不幸的是TimeOperation不是唯一的,不一定按照升序排列,所以我需要保持IntID作爲主鍵。 非常感謝。 –

0

最基本的索引在後臺創建一個「hypertree」結構層,它允許SQL引擎更容易地爲索引列找到具有特定值的行。每個索引都使用二進制搜索(logN性能)創建了「向下鑽取」表格數據的不同方式。您添加的每個索引都會使該索引更快地選擇,代價是放慢插入/更新(數據必須放入,然後必須創建索引)。

因此,通常應該爲通常用於過濾記錄的列的組合創建索引。我確實會在TimeOperation和TimeOperation上創建一個索引。

從不簡單創建索引,包括表中的所有列,尤其是像這樣的寬列。

+0

我已經單獨創建了TimeOperation索引,但是像「從mytable中選擇頂級1 *,其中field1 = 5的順序由TimeOperation DESC」來獲取最新的行,其中field1 = 5最多需要8秒(800萬行表) –