Sql-Server

不使用索引和其他一些東西的大型數據庫的可行性

  • February 13, 2020

我將盡可能簡要地解釋我的情況。我的團隊正在為另一家公司工作,我主要創建用於製作報告的儲存過程。

不同的是,上個月,他們決定進行一些重大更改,這大大增加了之前執行良好所需的時間。我不知道細節,但最大的變化之一是以前的表現在是從外部源獲取數據的視圖。這些定義為:

CREATE view [dbo].[eng_contra_env] as 
select ce_serial, ce_empresa, ce_ganado, ce_contra, ce_fecha_env, ce_fecha_rec, ce_observa
 from OPENROWSET('MSDASQL', '***', 'SELECT * from eng_contra_env');
GO

此外,自從那次改變以來,我不能做一些基本的事情,比如索引一些表,因為我的老闆告訴我不要這樣做,因為客戶做了這些改變。

所以,我被要求提高某些程序的性能(同樣,在完成更改之前,現在沒有)。該過程的一部分要求我執行以下操作:

https://www.brentozar.com/pastetheplan/?id=SkDJAvZQI

我應該如何優化它?另外,根據我已經說過的,您認為在這些條件下工作的可行性有多大。

**更新:**顯然他們在客戶那裡開了個會,他們決定恢復這些更改。感謝上帝!

使用由連結伺服器查詢支持的視圖會使您處於非常困難的境地。您會從“遠端查詢”運算符中得到糟糕的基數估計(估計為 10k 行,而實際值分別為 521k 和 30k)。這導致 SQL Server 選擇排序和使用合併連接,而如果估計更好,它可能會選擇散列連接。

對於此特定查詢,您可以嘗試使用雜湊連接提示來避免排序 + 合併連接計劃:

From  eng_facven A
   inner hash Join
  eng_facved B On A.fv_serial = B.fd_serial 

作為一般解決方案,您可以考慮首先將遠端表具體化為臨時表。這將為您提供更好的估計,從而可能提供更好的計劃。

當然,這個選項的可行性很大程度上取決於數據的大小/行數。在上面引用的查詢中,您只需將大約 16 MB 的總大小載入到臨時表中,這可能是合理的 - 特別是對於可能每天只執行一次或每天執行幾次的報告。

您提供的範例查詢如下所示:

SELECT *
INTO #eng_facven
FROM eng_facven;

SELECT *
INTO #eng_facved
FROM eng_facved;

Select  A.fv_empresa, A.fv_ganado, A.fv_contra
  , Sum(A.fv_animales)        fv_animales
  , Sum(A.fv_primales)        fv_primales
  , Sum(B.fd_prima)/Nullif(Sum(A.fv_animales),0)  fv_prima_total
  , Sum(B.fd_kilos)         fv_kg_factu
  , Sum(B.fd_bruto)         fd_precio
  , Sum(A.fv_imp_dto_trans)       fv_dto_fac

  , (Sum(B.fd_bruto) - Sum(A.fv_imp_dto_trans))
   /
   Nullif(Sum(B.fd_kilos),0)       fv_fd_prec_kg_canal


From  #eng_facven A
   Join
  #eng_facved B On A.fv_serial = B.fd_serial 

Group by A.fv_empresa, A.fv_ganado, A.fv_contra;

對於較大的表,您可能需要考慮安排一個計劃(每天/每小時)作業,將遠端表的內容複製到本地表中,並讓您的查詢引用這些。這取決於您的報告需要的最新程度。

最大的變化之一是以前的表現在是從外部源獲取數據的視圖。

所以數據已經從一個數據庫移動到另一個數據庫,但您仍在通過原始數據庫查詢它。這可能是客戶有意為之,他們打算繼續保持兩者,或者您可能會發現您現在正在使用客戶打算在某個時間點擺脫的數據庫

$$ perhaps not too distant $$未來! 您確實需要與客戶交談並找出他們更改的內容,以便盡可能**從新位置獲取數據。

這也令人擔憂:

CREATE view ... as 
select ce_serial, ce_empresa, ce_ganado, ce_contra, ce_fecha_env, ce_fecha_rec, ce_observa
from OPENROWSET('MSDASQL', '***', 'SELECT * from eng_contra_env');

這可能是另一個違反“規則”的情況:

切勿在生產程式碼中使用select * 。

您的視圖正在返回七個欄位。您不知道在 eng_contra_env 表中可以定義多少個欄位(現在或將來)。可能有數百個欄位,每個欄位都可能包含大量數據,所有這些數據都被您的視圖定義通過網路拉回,以實現絕對零收益。

始終明確指定要檢索的列。

引用自:https://dba.stackexchange.com/questions/259511