2009-06-03 106 views
1

我在Microsoft SQL Server 2008中遇到了一個奇怪的問題。 我有一個大型數據庫(20 GB),包含大約10個表,我試圖就如何正確地創建索引提出一個觀點。SQL Server 2008性能:沒有索引與不良索引?

這是我的問題:在一些嵌套查詢我得到更快的結果沒有使用索引!它接近(一兩秒),但在某些情況下,根本不使用索引似乎會使這些查詢運行得更快......我正在運行一個Checkpoiunt和一個DBCC dropcleanbuffers來在運行腳本之前重置緩存,米有點失落。

這可能是什麼原因造成的? 我知道這樣一個事實,即索引構造不好(想想每個相關領域的索引),整點就是要證明正確構建它們的重要性,但它應該比完全沒有索引要慢, ?

編輯:這裏是有罪的查詢之一:

SET STATISTICS TIME ON 
SET STATISTICS IO ON 

USE DBX; 
GO 
CHECKPOINT; 
GO 
DBCC DROPCLEANBUFFERS; 
GO 
DBCC FREEPROCCACHE; 
GO 

SELECT * FROM Identifier where CarId in (SELECT CarID from Car where ManufactId = 14) and DataTypeId = 1 

標識表: - IdentifierId INT NOT NULL - CarId INT NOT NULL - DataTypeId INT NOT NULL - 別名爲nvarchar(300)

車表: - CarId INT NOT NULL - ManufactId INT NOT NULL - (幾個領域緊隨其後,所有的數據類型爲nvarchar(100)

這些項目符號中的每一個都有一個索引,以及一次同時存儲其中兩個索引的一些索引(例如, CarId和DataTypeId)。

最後,識別符表已超過萬個條目,而車表有兩三萬

+0

感謝所有答案的傢伙! 不幸的是,SQL Server認爲數據庫應該被徹底恢復,所以我很害怕暫時被鎖定。 PS:我還刪除了「無索引」方法中的主鍵,但在索引很差的索引中重建了它們 – 2009-06-03 14:58:02

回答

4

我的猜測是,SQL Server不正確地決定使用索引,然後強制書籤查找*。通常發生這種情況時(索引使用不正確)是因爲表上的統計數據不正確。如果你剛剛加載大量數據到一個或多個表的

這尤其可以發生。或者,它可能是SQL Server剛剛搞砸了。發生這種情況非常罕見(我可以一方面指望我在SQL Server的15年職業生涯中必須強制索引使用的時間),但優化器並不完美。

*書籤查找是當SQL Server發現一排,它需要一個索引,但隨後去實際的數據頁檢索不在索引附加列。如果結果集返回很多行,則這可能代價高昂,並且聚集索引掃描可能會導致更好的性能。

一種方法來擺脫書籤查找的是使用覆蓋索引 - 它首先具有過濾列的索引,但後來也包括你需要在「覆蓋」查詢的任何其他列。例如:

SELECT 
    my_string1, 
    my_string2 
FROM 
    My_Table 
WHERE 
    my_date > '2000-01-01' 

覆蓋指數會(my_date,my_string1,my_string2)

+0

想到這一點,儘管自創建索引以來沒有執行插入操作 – 2009-06-03 16:09:20

+0

關於覆蓋索引,如果我搜索my_string1和my_string2,可以涵蓋索引提供了答案? – 2009-06-03 16:10:20

+1

它有時會使用索引,儘管my_string1和my_string2不在索引的開頭,它必須是索引掃描。想象一下,在電話簿中尋找有「a」作爲他們姓氏的第二個字母的人。跳到可能具有該部分(「aa」,「ba」等)的每個部分,而不是掃描整個電話簿的速度會更快,但速度並不像通過首字母查找名稱那麼快。 – 2009-06-03 16:54:00

0

檢查執行計劃,看它是否正在使用這些指標,你「知道」一個是壞?

通常,索引會減慢寫入數據的速度,並有助於加速讀取數據。

所以是的,我同意你的看法。它應該從來沒有比根本沒有索引慢。

1

通常,SQL Server在決定使用哪種索引(如果有的話)以最快的方式檢索數據方面做得很好。很多時候它會決定不使用任何索引,因爲它可以更快地從小表中檢索少量數據,而不必離開索引(在某些情況下)。

這聽起來像你的情況SQL可能不會採取最優路線。有很多嚴重創建的索引可能會導致它選擇錯誤的路線來獲取數據。

我會建議查看管理工作室的查詢計劃,以檢查其使用的索引和時間正在採取。這應該給你一個好主意從哪裏開始。

另一個需要注意的是,也許是這些指標已經得到碎片隨着時間的推移,現在未能發揮最好的,這也許值得一試這一點,如果需要重建他們中的一些。

1

索引直到您有很多記錄才真正沒有任何好處。我說很多,因爲我真的不知道這個轉折點是什麼......它取決於具體的應用和情況。

SQL Server需要時間才能使用索引。如果那個時間超過了好處......這在子查詢中尤其如此,其中小的差異將會倍增。

如果在沒有索引的情況下效果更好,則省略索引。

+0

對於SQL 2000,它大約有134行。並不是那麼多。 – gbn 2009-06-03 14:43:26

1

嘗試DBCC FREEPROCCACHE以清除執行計劃緩存。

+0

@ gbn + 1:迄今爲止最明智的評論。 1秒的差異可能是初始查詢的編譯成本:-)我還建議你(SET STATISTICS IO ON)開始查看邏輯和物理讀取的數量以及(SET STATISTICS TIME ON),以準確地監視時間。 – 2009-06-03 14:44:53

+0

添加到查詢,只是等待恢復....該死,糟糕的時機:S – 2009-06-03 15:04:34

1

這是一個空洞的猜測。也許如果你有很多索引,SQL Server會花時間分析和挑選一個,然後拒絕所有這些索引。如果你沒有索引,引擎就不用浪費時間進行這個審查過程。

這個審查過程實際需要多長時間,我不知道。

1

對於某些查詢,直接從表中讀取(聚簇索引掃描)要快於讀取索引並從表中讀取記錄(索引掃描+書籤查找)。

請考慮記錄與數據頁中的其他記錄一起存在。 Datapage是IO的基本單位。如果直接讀取表格,則可以獲得10個記錄,其中包含1個IO的成本。如果直接讀取索引,然後從表中提取記錄,則必須爲每條記錄支付1 IO。

通常SQL服務器非常擅長挑選訪問表的最佳方式(直接與索引)。您的查詢中可能有一些盲目優化器。查詢提示可以指示優化器在錯誤時使用索引。加入提示可以改變表的訪問順序或方法。表變量被優化器認爲有0條記錄,所以如果你有一個大的表變量 - 優化器可能會選擇一個壞計劃。

還有一件事要注意 - varchar vs nvarchar。確保所有參數與目標列的類型相同。在發生類型不匹配的情況下,SQL Server會將的整個索引轉換爲參數的類型。

+0

嗯,我看到了,雖然我沒有使用不同類型的列和表變量。儘管 – 2009-06-03 15:07:07

0

SQL服務器實際上爲您創建了一些索引(例如,在主鍵上)。

索引可能變成碎片。

索引過多會一直降低性能(有上爲什麼不能索引在數據庫中每一個山坳常見問題解答)

也有s個ome situations where indexes will always be slower

+0

已被殺死,但主鍵和索引都是「新建」的:S – 2009-06-03 15:07:37

0

運行:

SET SHOWPLAN_ALL ON 

,然後運行使用和不使用索引使用您的查詢,這將讓你看看是否有任何正在使用什麼指標,這裏的「工作」是在等

0

沒有SQL服務器決定使用一個索引來加速查詢之前分析這兩個指標和統計數據。運行非索引版本完全有可能比索引版本更快。

有幾件事情來嘗試

  1. 確保創建和重建索引,重新組織(整理)。

  2. 確保自動創建統計信息被打開。

  3. 嘗試使用SQL事件探查器捕獲調整配置文件,然後使用數據庫引擎優化顧問創建索引。

令人驚訝的是,Sql管理的MS Press考試書很好地解釋了索引和統計數據。在這本書的讀者亞馬遜預覽的內容

見第4章表

Amazon Reader of Sql 2008 MCTS Exam Book

0

對我來說,這聽起來像你的SQL編寫很差,因此不利用你所創建的索引。

你可以直到你臉色發青添加索引,但如果您的查詢不優化以充分利用這些索引,那麼你不會得到任何性能增益。

給我們一個您正在使用的查詢的示例。

好嗎?

試試這個,看看你得到任何性能提升(與PK索引)

SELECT i.* 
FROM Identifier i 
    inner join Car c 
     on i.CarID=c.CarID 
where c.ManufactId = 14 and i.DataTypeId = 1 
+0

完成,檢查出來 – 2009-06-03 15:50:09

+0

會做什麼,還在等待恢復...加耶 – 2009-06-03 16:50:23