2015-08-27 17 views
2

我有一個表,有很多行(300萬),我需要從我的應用程序中的幾個點查詢一些行。我發現這樣做的方式是首次查詢所有需要的數據,並將其存儲在static DataTableSqlAdapter.Fill()的應用程序餘下時間。如何從SQL Server緩存一個大表

這很快,因爲那時我需要使用DataTable.Select("some query"),應用程序處理的信息很好。

問題是這張表需要大約800MB的RAM,我必須在PC上運行這個應用程序,它可能太多了。

我認爲的另一種方式是每次查詢我需要的數據。這需要很少的內存,但性能較差(對數據庫的很多查詢,這是在一個網絡地址,並有1000個查詢,你開始注意到ping和所有這些..)。

性能和內存使用率之間是否存在中間點?


編輯:我正在檢索的是銷售,其中有一個日期,產品和數量。我按產品查詢,並沒有以這種方式索引。但無論如何,作出1000個查詢,即使查詢花了0.05s,0.2s ping總共200秒...

+8

數據庫性能調優的一般規則是僅檢索所需的數據,然後圍繞該數據設計索引策略。聽起來你不是這樣做的;你可以提供更多關於正在運行的查詢和正在使用的索引的詳細信息嗎? –

+0

在這裏有一個類似的帖子,檢查http://stackoverflow.com/questions/23816130/forcing-sql-server-to-pre-cache-entire-database-into-memory – sriharichander

+0

這是一個想法:使用delta拉動。只提取需要的數據並將其存儲在集合中,繼續操作。當然,在發送請求獲取數據之前,如果您的查詢關鍵字已經存在於您的現有集合中,請比較它們。 – singsuyash

回答

0

RE:「我不能索引任何東西,因爲我不是數據庫管理員也不能要求那樣。「

你能預先填充臨時表和索引嗎?

Select * into #MyTempTable from BigHugeTable 
Create Index Prodidx on #MyTempTable (product) 

你必須確保你總是重複使用相同的連接(而不是關閉),以使用臨時表。

+1

或者一個全局/ tempdb表 - http://stackoverflow.com/a/2921091/16391 – StingyJack

1

這個問題可以歸結爲內存vs性能。答案是緩存


如果你知道你的使用模式將是什麼樣的,然後有一兩件事你可以做的是在應用中創建一個本地緩存。

極端情況是 - 您的緩存大小爲800MB,其中包含所有數據(從而犧牲內存) - 或者 - 您的緩存大小爲0MB,並且所有查詢都會進入網絡(從而犧牲性能)。

下面回答了關於緩存設計的三個重要問題。


如何填充緩存?

  1. 如果你很可能使某些查詢多次,將其存儲在緩存和睡前網絡,測試,如果你的緩存中已經有結果。如果沒有,請查詢數據庫,然後將結果存儲在緩存中。
  2. 如果在查詢某些數據後,您可能會查詢下一個和/或之前的數據,然後查詢所有數據並緩存它,以便在查詢下一個數據塊時,您已將其存儲在緩存中。

如果您知道將來可能需要某些信息,請事先對其進行緩存,但實際上這個想法是


如何釋放緩存?

你可以決定的釋放機制緩存或者積極被動

被動式:只要緩存滿了,您可以從中刪除數據。

活躍:定期運行一個後臺線程,併爲您負責移除後臺線程。

一種混合方法是在你到達時運行一個釋放線程,比如說,80%的內存限制,然後釋放你所能做的任何內存。


什麼數據從緩存中刪除?

這已經在操作系統的Page Replacement Policies問題的背景下得到了回答。

完成,我會總結了重要的位置:

  1. 驅逐最近最少使用數據(如果它是不可能被使用);
  2. 退出最早帶來的數據(如果最早的數據不可能被使用);
  3. 逐出最近帶來的數據(如果您認爲新引入的數據最不可能被使用)。
  4. 自動刪除早於t時間單位的數據。
3

先說說關於表現的

的DBA

如果你下載的是整個表,你實際上可能把網絡和SQL比,如果你進行個人查詢更多的負荷。

作爲一名dba,如果我知道您正在下載整個大型表格,我會立即在產品上添加索引。

你爲什麼要執行1000次查詢?

如果您在創建產品時查找銷售額,則緩存存在問題。你還沒有銷售數據。緩存的問題是陳舊的數據。如果你知道數據不會改變 - 你要麼沒有,那麼你可以消除過時數據的擔憂。

有順序和同時之間的東西。您可以在一個請求中打包多個選擇。這樣做只是一次往返,而且效率更高。

select * from tableA where ....; 
select * from tableB where ....; 

隨着DataReader的只是調用SqlDataReader.NextResult Method()

using (SqlDataReader rdr = cmd.ExecuteReader()) 
{ 
    while (rdr.Read()) 
    { 
    } 
    rdr.NextResultSet(); 
    while (rdr.Read()) 
    { 
    } 
} 

敢肯定你可以在DataSet中的多個數據表做同樣類型的東西。

另一種選擇是LocalDB。它針對的是開發人員,但是對於你正在做的事情來說,它會工作得很好。數據錶速度沒有內存問題。您甚至可以在ProductID上放置索引。與內存相比,寫入光盤需要更長的時間,但是您沒有使用內存。

然後有(nolock)永遠的邪惡。知道你在做什麼,我不會去探究所有可能的罪惡,但我可以告訴你,我使用它很多。