資訊: 特殊查詢效能的疑難排解

文章翻譯 文章翻譯
文章編號: 243588 - 檢視此文章適用的產品。
本文曾發行於 CHT243588
全部展開 | 全部摺疊

在此頁中

結論

本文介紹一種在 Microsoft SQL Server 中可能遇到的特定類型的效能問題,即大量同時發出的特殊查詢所造成的低效能問題。如果您正在進行效能問題的疑難排解,但還不能確定這是否為真正的問題所在,請在繼續進行前參閱「Microsoft 知識庫」中的下列文章:

224587資訊:SQL Server 應用程式效能疑難排解
本文的其它內容假設您已經使用了上述文章縮小了問題的範圍,並且已擷取了「Windows NT 效能監視器」記錄及「SQL Server 分析工具」追蹤中的特定計數器、事件和其中的資料行。 本文中討論的特定效能問題具有下列特點:
  • 通常進行時間很短的短特殊查詢,在很多使用者同時執行時,導致整體系統效能降低。
  • CPU 使用率很高或達到 100%。
  • 處於低效能時無相關鎖定。

    可以檢查 sp_who 系統預存程序輸出中的 BLK 行,以快速地檢查鎖定。如果一些系統處理 ID (SPID) 的 BLK 行不是零,則表明正處於鎖定狀態。如需關於鎖定問題的詳細討論,請參閱「Microsoft 知識庫」中的下列文章:

    224453資訊:了解並解決 SQL Server 7.0 之鎖定問題
  • 在某些情況下,伺服器記憶體的使用量持續加壓,並報告下列資訊:

    錯誤:701,嚴重度:17,狀態:1
    沒有足夠的系統記憶體來執行這項查詢。(Error: 701, Severity: 17, State: 1 There is insufficient system memory to run this query.)
    -或-
    Msg 8645、層級 17、狀態 1、程序、行 1
    等待執行查詢所用的記憶體資源時發生逾時。請重新執行該查詢。(Msg 8645, Level 17, State 1, Procedure , Line 1 A time out occured while waiting for memory resources to execute the query. Re-run the query.)
    下述各種情況不一定都會出現上述症狀。

其他相關資訊

由於 SQL Server 的系統架構 (尤其是查詢最佳化器) 從 SQL Server 7.0 開始便有所改進,所以與以前版本的 SQL Server 相比,應用程式在系統資源的使用上有很大差異。具體而言,SQL Server 7.0 可能會在 CPU 或記憶體的使用量上有所增加,而以前版本的 SQL Server 通常是受磁碟 I/O 的束縛。這些變化可以歸究為兩個因素:雜湊聯結與合併聯結,以及查詢編譯時間。

以前版本的 SQL Server 只依賴於巢狀迴圈反覆運算來執行聯結。巢狀迴圈聯結本身使用磁碟 I/O。從 SQL Server 7.0 開始,除巢狀迴圈聯結外,還引入雜湊和合併聯結。在記憶體處理上,雜湊和合併聯結比巢狀迴圈聯結的功能要強許多。在使用這些聯結技術時,其邏輯結果是 CPU 和記憶體的使用率要變高。有關雜湊和合併聯結的詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 Understanding Hash Joins 和 Understanding Merge Joins 主題。

由於查詢最佳化器比以前版本有更多的選項和資訊(新的雜湊和合併聯結技術、改進的搜尋演算法及行計算),查詢編譯時間將因此受影響。 這些附加資訊使得最佳化器有更多的機會來選擇最為有效的計劃取出查詢資料。然而,分析與考慮這些新技術和資訊需要佔用處理時間。這種提高的 CPU 使用率將導致查詢編譯時間要長於以前版本。

對於大多數查詢來說,編譯時間的增加可以透過降低執行時間來補償。整體效果是查詢執行速度比以前的版本更快。然而,有一種情況例外:即只需要很短執行時間的非常小而簡單的 OLTP 類型查詢。對於這些情況,產生查詢計劃的處理程序可能比執行查詢要花費更多的時間或相同的時間。結果,查詢將比以前版本執行得稍微慢一些。由於這種差別通常在毫秒級內,對於某個指定的查詢來說,如果單獨執行,便不會發現這種小的差別。然而,如果許多使用者同時執行大量特殊查詢,系統 CPU 的總使用率便會比以前版本的 SQL Server 要高。 SQL Server 7.0 採用一些新技術來減少這種影響,如將特殊查詢存入快取記憶體及自動參數化。然而,可用於自動參數化的查詢選擇是有限的。應用程式開發人員可採用下列方法來保證所開發的查詢計劃能參數化並可更有效地重複使用。
  • 參數標記
    OLE-DB 和 ODBC API 都允許在送出查詢時,指定具有問號的參數。這對任何應用程式都很有用,特別是那些具有查詢產生模組的中介層的應用程式,因在這些程式中無法使用預存程序。而為執行時使用參數標記的查詢所產生的查詢計劃,還可由其後執行相同查詢的用戶端重複使用,就算指定的是不同的參數值也沒有關係。如需詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 Parameter Marker 主題。
  • sp_executesql
    在應用程式中使用參數標記時,OLE DB 提供者或 ODBC 驅動程式會呼叫 sp_executesql 預存程序。然而,應用程式也可直接呼叫該系統程序或在另一個預存程序中進行呼叫,以明確地用參數表示特殊查詢。這在使用 EXECUTE 陳述式來執行動態 SQL 陳述式的應用程式或批次檔中,十分有用。與 sp_executesql 不同,EXECUTE 陳述式不允許進行參數化,這會限制查詢計劃的重複使用。如需詳細資訊,請參閱下面的討論以及 SQL Server 7.0 Books Online 中的 sp_executesql (T-SQL) 和 Using sp_executesql 主題。
  • 預存程序
    預存程序有很多優點,其中包括參數化查詢以及重複使用執行計劃。如需詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 Stored Procedures 和 Programming Stored Procedures。

辨識並解決這些效能問題



如果還沒有這麼做,請參見「Microsoft 知識庫」中有關擷取「Windows NT 效能監視器」和「SQL Server 分析工具」的文章,以協助分析系統效能:

224587資訊:SQL Server 應用程式效能疑難排解

檢視效能監視器資料



使用「效能監視器」記錄來判斷何者系統資源遇上了瓶頸。這可以幫助您了解整個系統情況,並將精力集中於檢視「分析工具」資料。效能良好時檢視「效能監視器」資料,效能降低時檢視計數器的趨勢。哪個計數器最先有不好的影嚮呢? 了解此資訊有助於確定出現的情況與下列哪個問題有關。在下面討論的問題中應考慮下列的計數器:

  • Object: Process
    Counter: Processor
    Instance: SQL Server

  • Counter: %Processor Time
    Instance: Check each processor instance
  • Object: SQL Server:Buffer Manager
    Counter: Free Buffers
  • Object: SQL Server:Buffer Manager
    Counter: Stolen Page Count
  • Object: SQL Server:Memory Manager
    Counter: Memory Grants Pending
  • Object: SQL Server:SQL Statistics
    Counter: SQL Compilations/sec

如果 CUP usage (CPU 使用率)、SQL Compilations/sec (每秒 SQL 編譯數) 和 Free Buffers (可用緩衝區) 很高,而 Memory Grants Pending (擱置的記憶體授權) 和 Stolen Page Count (遺失的頁數) 很低,則表示 CPU 處於瓶頸狀態。 根據下列步驟來有效地參數化和重新使用查詢計劃,以避免重新生成查詢計劃的開銷(請參見本文的「通過'事件類'分組'分析工具'追蹤」)。如果 Free Buffers 和 SQL Compilations/sec 很低,而 Stolen Page Count 和 Memory Grants Pending 很高,則表明 SQL Server 記憶體有限。集中尋找使用雜湊聯結並可變更為迴圈聯結的查詢(請參見本章的「通過'持續時間'分組'分析工具'追蹤」)。

如需上述計數器的詳細資訊,請在 SQL Server 7.0 Books Online 中搜尋計數器名稱。

檢視分析工具資料



在解效能問題時有效地檢視「分析工具」資料是非常有用的。最重要的是您無需檢視每個擷取到的資料,而只是有選擇地檢視。「分析工具」提供的功能可幫助您有效地檢視擷取的資料。您可在「分析工具」的 [屬性] 索引標籤 (在 [檔案] 功能表上,按一下 [屬性]) 上移除資料行或事件、依資料行分組 (排序) 及套用篩選條件,以限制顯示的資料。也可在 [編輯] 功能表上按一下 [尋找],以搜尋整筆追蹤記錄或只搜尋特定數值的資料行。也可以在 [檔案] 功能表上,指向 [另存新檔],然後按一下 [追蹤表],將「分析工具」資料儲存到 SQL Server 表中,並對其執行 SQL 查詢。

注意:請確定您 只在以前儲存過的追蹤檔案上執行篩選 如果在某個主動追蹤上執行這些步驟,則由於已經啟動追蹤,將會有遺失已擷取資料的危險。請先在 [檔案] 功能表上,按一下 [另存新檔],將主動追蹤儲存至檔案或表,然後在繼續執行前重新開啟此追蹤 (在 [檔案] 功能表上按一下 [開啟])。在篩選已經儲存的追蹤檔案時,並不會永久移除篩選出的資料,而只是不顯示這些資料。您可以根據需要來新增和刪除事件及資料行,以集中搜尋的範圍。

另一個重要的問題是要將精力集中於獲益最多的地方。下面所行的因素能將有助於提高應用程式效能,但在程度上並不一定相同。在開始實施更改前,檢查下列所有項以確定其提高效能的潛力。 任何更改所帶來的影響主要依賴於兩個因素:
  • 執行有問題查詢的頻率。
  • 查詢效率的提高程度。
如果並不經常執行某查詢,則將其執行時間減少 1.5 至 1.2 秒,效果並不明顯。 然而,如果大量的使用者經常同時執行該查詢,則效能的提高是非常顯著的。 相反地,如果不經常使用某項單一查詢,而將其執行時間減少 6 分鐘至 3 秒,則在整體效能上並不會有很明顯的改善。在執行下面討論的補救措施之前,請使用「分析工具」中的分組和篩選技術,來估計某個指定查詢或程序的影響。首先集中於影響最顯著的更改,然後繼續反覆運算其它查詢及程序,直到效能有足夠的改善為止。

如果沒有擷取到「分析工具」追蹤,請參閱「Microsoft 知識庫」中的下列文章,了解如何使用適當的事件和資料行來建立追蹤記錄:

224587資訊:SQL Server 應用程式效能疑難排解
將「分析工具」追蹤記錄儲存至檔案或表中後,請在「分析工具」中將其重新開啟,並開始檢查其內容。
  • 根據持續時間來為分析工具追蹤分組:

    1. [檔案] 功能表上,按一下 [屬性]
    2. [資料行] 索引標籤上,使用向上按鈕來移動 [群組] 標題下的 [持續時間]。使用向下按鈕刪除 [群組] 標題下的所有其它行。
    3. [事件] 索引標籤上,移除除了 TSQL SQL:StmtCompletedTSQL RPC:Completed 之外的所有其它事件。這可讓您只集中於要執行的查詢。
    4. 按一下 [確定]
    根據持續時間進行分組,可以很容易看出哪些 SQL 陳述式、批次處理或程序執行地最慢。有一點很重要,即不僅要看到問題何時發生,而且要建立一條基線,以判斷效能是否良好。您可以根據啟動時間進行篩選,以便在效能良好時將追蹤分為多個部分,而在效能降低時將追蹤分為獨立的區段。尋找在效能良好時,持續時間最長的查詢。這最有可能是問題的根源所在。當整個系統效能降低時,即使是好的查詢在等待系統資源時也會顯示很長的持續時間。

    檢視執行計劃,尋找經常出現長持續時間的查詢。如果使用了雜湊聯結,請考慮使用 LOOP JOIN 查詢提示來強迫查詢使用巢狀迴圈聯結。 如果使用迴圈聯結的查詢執行時間小於或等於或者稍微大於雜湊聯結的執行時間,則當電腦具有高記憶體及 CPU 使用率時,選用迴圈聯結可能會更好。透過減少資源瓶頸 (CPU 和/或記憶體) 的壓力,可以提高整個系統效能。如需關於 LOOP JOIN 提示的詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 SELECT (T-SQL) 主題。

    如果發現某個查詢具有不正常的長持續時間,請參閱「Microsoft 知識庫」中的下列文章:

    243589資訊:在 SQL Server 7.0 或更新版本上的執行緩慢查詢疑難排解
  • 根據事件類別來為分析工具追蹤分組:

    1. [檔案] 功能表上,按一下 [屬性]
    2. [資料行] 索引標籤上,使用向上按鈕移動 [群組] 標題 (上面有 [事件類別]) 下的 [事件類別][文字]。使用向下按鈕刪除 [群組] 標題下的所有其它行。
    3. [事件] 索引標籤上,確保包含了所有的事件。
    4. 按一下 [確定]

    根據 [事件類別] 行進行分組會顯示出發生於 SQL Server 上的事件類型及頻率。請在此行中搜尋下列事件:

    • MISC: Prepare SQL and Exec Prepared SQL; CURSORS: CursorPrepare

      Prepare SQL 事件透過預設的游標選項 (只轉送、唯讀、列集大小 = 1),使用 SQLPrepare/SQLExecute (對於 ODBC) 或 ICommandText::Prepare/ICommandText::Execute (對於 OLE DB) 來指明具有預設結果集 (用戶端游標) 的可使用 SQL 陳述式。Cursorprepare 事件透過將上述其中一個游標選項設定為非預設值,使用 SQLPrepare/SQLExecute (對於 ODBC) 或 ICommandText::Prepare/ICommandText::Execute (對於 OLE DB) 來指明具有預設結果集 (伺服器端游標) 的可使用的 SQL 陳述式。Exec Prepared SQL 事件指明執行上述類型的可執行陳述式。如果您發現經常出現這些事件,則開啟結果集時應用程式使用「準備/執行」模型。若如此,則下一個問題是:

      您是否有正確使用準備/執行模型?

      理想情況下,應用程式應一次準備一個 SQL,且加以多次執行。這樣,每次執行陳述式時,便節省了最佳化器編譯新計劃的時間。每次執行準備好的陳述式時,您也節省了查詢編譯的時間。如果一次計劃只執行一個查詢,則不必準備 SQL 陳述式。準備一個 SQL 陳述式然後執行需要三個網路階段:準備陳述式、執行陳述式、解除準備陳述式。 準備伺服器端游標至少需要 5 個階段:準備游標、執行 (開啟) 游標、從游標中擷取 (一步或多步)、關閉游標、解除準備游標。簡單執行查詢只需要一個階段。如果不重新使用陳述式,則其它階段的工作並無益處。

      若要了解應用程式使用準備/執行模型的情況是否良好,請比較準備事件及執行事件發生的次數。Exec Prepared SQL 事件的次數應大於 Prepare SQL + CursorPrepare 事件的總次數 (至少為 3 到 5 倍為好)。這表示重複使用準備好的陳述式的次數夠多,而可以克服建立陳述式的負擔。如果 Prepare SQL + CursorPrepare 事件的數量大大約等於 Exec Prepared SQL 事件的數量,則表示應用程式沒有很好地利用準備/執行模型。您不應準備將只執行一次的陳述式。相反地,應該準備某個陳述式,然後盡可能重複使用。如果必要的話,請準備陳述式,且在可能時重複地使用該陳述式來更改應用程式,以便將準備/執行模型的效能發揮地更好。

      注意:應特意編寫應用程式以使其有效地使用準備/執行模型。一個已準備好的陳述式控制碼的生存週期,是由在 ODBC 中使 HSTMT (或在 OLE DB 中使 ICommandText 物件) 保持開啟的時間長短而定。通常的做法是:取得 HSTMT、準備 SQL 陳述式、執行準備好的陳述式,然後釋放 HSTMT,也因而遺失了準備計劃的控制碼。如果是這樣的話,您便沒有利用準備/執行模型的任何優點。事實上,由於前面所述的網路階段會增加額外開銷,效能反而會降低。應用程式需要藉由某種方法,將具有已準備好陳述式控制碼的物件或 HSTMT 存入快取,並加以重複存取。這項工作不會由驅動程式或提供程式自動完成,而是需要應用程式來實現、維護並使用該資訊。如果應用程式不能完成此工作,可考慮使用參數標記,而非準備和執行。 使用參數標記

      有了參數標記,在使用不同的輸入輸出值來多次執行同一 Transact-SQL 陳述式時,應用程式就能對其進行最佳化。第一次執行某個查詢時,它是一個參數化查詢,SQL Server 會為查詢產生參數化計劃,並將該計劃存入快取。如果稍後使用相同或不同的參數來呼叫同一查詢,SQL Server 便不需產生新的查詢計劃,而可以取代目前的參數來重複使用現有的計劃。這樣,每次重複使用現有查詢時,便節省了產生查詢計劃的時間。

      在使用呼叫 SQLExecDirect (ODBC) 或 ICommandText::Execute (OLE DB) 的參數標記時,驅動程式或提供程式會封裝 SQL 陳述式,並將其當作 sp_executesql 呼叫來執行。您無需特地個別地準備和執行該陳述式。當 SQL Server 收到對 sp_executesql 的呼叫時,它會自動檢查現有符合計劃的程序快取,並在可能情況下重複使用該計劃;如果沒發現計劃,便會建立新計劃。

      若要確定應用程式目前是否使用參數標記,可以在「分析工具」追蹤的 [文字] 行中搜尋 sp_executesql。然而,由於 sp_executesql 可能被直接呼叫,並非所有的實例都代表有使用參數標記。

      如需關於準備/執行模型的詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 Execution Plan Caching and Reuse 主題。如需關於參數標記的詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 Parameter Markers 主題。
    • SP:Completed

      使用 EXECUTE 指令來執行的動態 SQL 陳述式,將顯示為具有動態 SQL 文字的 SP:Completed 事件。請展開 SP:Completed 事件並搜尋所有具有「動態 SQL」的事件。如果具有大量的這類事件,則可能可以使用 sp_executesql 來替代 EXECUTE 陳述式,藉以提高應用程式效能。如果是以不同的參數來重新執行相同的查詢,則 sp_executesql 會允許 SQL Server 重複使用執行計劃。如果使用 EXECUTE 陳述式,則計劃沒有參數化,所以只有以完全相同的參數重新執行查詢時,才能重複使用該計劃。

      若要判斷哪一個查詢或程序有透過 EXECUTE 陳述式來使用動態 SQL,請注意事件出現的 ConnectionID 和 Start Time。請從 [群組] 標題中刪除 [事件類別][文字],以取消追蹤的分組。這會傳回按時間順序排列日期的追蹤。您可以在指定 Connection ID 上的 [篩選] 索引標籤上篩選追蹤,刪除 SP:StartingSP:Complete 的所有「事件類別」,使陳述式較易閱讀。然後在之前 Start Time 的 [編輯] 功能表上,按一下 [尋找] 來進行搜尋。這將準確顯示動態 SQL 事件開始的位置。如果該事件位於預存程序中,則該事件將在程序的 SP:StartingSP:Completed 事件之間發生;否則,就會被當作特殊查詢來執行。您可以使用資料行 (如:[應用程式名稱][NT 使用者名稱] 等) 來確定指令執行的位置。也可以重新新增「事件類別」(例如:SQL:BatchCompletedSQL:RPCCompleted) 來確定指令的文字及其執行的內容。

      確定執行 EXECUTE 陳述式的位置後,請考慮用對 sp_executesql 的呼叫來取代這個陳述式。例如,請考慮以下在動態 SQL 中執行 EXECUTE 指令的情況。某個程序以表名、ID 及 idValue 作為輸入參數,並從基於 ID 值的表來執行 SELECT 陳述式。使用 EXECUTE 陳述式的程序如下所示:
      drop proc dynamicUsingEXECUTE 
      go
      create proc dynamicUsingEXECUTE 
      @table sysname, 
      @idName varchar(10),
      @idValue varchar(10)
      as
      declare @query nvarchar(4000)
      -- Build query string with parameter.
      -- Notice the use of escape quotes.
      select @query = 'select * from ' + @table + ' where ' + @idName + ' = ''' + @idValue + ''''
      exec (@query)
      go
      
      假設該查詢不是自動參數化的,如果您以不同的 @idValue 參數值在 pubs 範例資料庫的 titles 表中執行該程序,則 SQL Server 需要為每個執行程序產生一個獨立的查詢。
      exec dynamicUsingEXECUTE 'titles', 'title_id', 'MC2222'
      go
      exec dynamicUsingEXECUTE 'titles', 'title_id', 'MC2222'
      
      注意: 在這種情況下,查詢相當簡單,SQL Server 可以將該查詢自動參數化並真正重新使用該執行計劃。 然而,如果是 SQL Server 不能自動參數化的複雜查詢,則當 @idValue 參數變化時,SQL Server 便不能重複使用計劃。該簡單查詢用於限制範例的複雜性。

      您可以重新編寫該程序以使用 sp_executesql 來代替 EXECUTE 陳述式。支援參數的取代使 sp_executesql 更有效,因為它產生更可能由 SQL Server 重複使用的執行計劃。
      drop proc dynamicUsingSP_EXECUTESQL 
      go
      create proc dynamicUsingSP_EXECUTESQL 
      @table sysname, @idName varchar(10), @idValue varchar(10)
      as
      declare @query nvarchar(4000)
      -- Build query string with parameter
      select @query = 'select * from ' + @table + ' where ' + @idName + ' = ''' + @idValue + ''''
      -- Now execute with parameter
      exec sp_executesql @query, 
      @idValue varchar(10)
      @idValue
      go
      
      exec dynamicUsingEXECUTE 'titles', 'title_id', 'MC2222'
      go
      exec dynamicUsingEXECUTE 'titles', 'title_id', 'MC2222'
      
      在這種情況下,第一次執行 sp_executesql 陳述式時,SQL Server 會從 titles (以 title_id 作為參數) 中的 SELECT 產生一個參數化計劃。第二次執行時,它就只會以新的參數值重複使用該計劃。

      如需關於 sp_executesql 的詳細資訊,請參閱 SQL Server 7.0 Books Online 中的 sp_executesql (T-SQL) 和 Using sp_executesql。
    • SP:RECOMPILES

      該事件指出某個預存程序在執行時被重新編譯。大量重新編譯事件代表 SQL Server 把資源花在查詢編譯上,而不是查詢執行上。如需關於解決預存程序重新編譯問題的詳細資訊,請參閱「Microsoft 知識庫」中的下列文章:

      243586〈INF:預存程序重新編譯疑難排解〉(INF: Troubleshooting Stored Procedure Recompilation)
    • 非上述任何事件

      如果您未看到上述任何事件,則應用程式只在 SQL Server 上執行了特殊查詢。除非 SQL Server 能確定可以自動參數化某些查詢,或者重複使用相同的參數,否則每個所執行的查詢均需要產生一個新的執行計劃。「效能監視器」會顯示大量的 SQL Compilations/sec。如上所述,如果是大量的使用者同時使用,便會需要大量佔用 CPU 資源。若要解決此問題,請尋找執行頻率最高的查詢,並為這些查詢建立預存程序,或者使用參數標記或 sp_executesql

參考資料



如需關於 SQL Server 7.0 中查詢效能問題的詳細資訊,請參閱位於 http://support.microsoft.com/?scid=ph;en-us;2862 的 SQL Server 7.0:查詢效能疑難排解。

如需關於使用「分析工具」的詳細資訊,請參閱 SQL Server 7.0 Books Online。

?考

本文件是根據 Microsoft Knowledgebase 文件編號 Q243588 翻譯的. 若要參考原始英文文件內容, 請至以下網址:

http://support.microsoft.com/support/kb/articles/Q243/5/88.asp

屬性

文章編號: 243588 - 上次校閱: 2006年7月6日 - 版次: 3.0
這篇文章中的資訊適用於:
  • Microsoft SQL Server 7.0 Standard Edition
  • Microsoft SQL Server 2000 Standard Edition
關鍵字:?
kbhowto KB243588
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。

提供意見

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com