1

現在、クエリとストアド プロシージャのパフォーマンスの問題に直面しています。シナリオは次のとおりです。

SQL Server 2000 SP4データベース ( ) には、膨大な量のレコードを持つ 3 ~ 4 個のテーブルがあります。テーブルの 1 つには、2,500 万を超えるレコードがあります。これらのテーブルは、販売記録を維持しており、毎日何千もの記録が追加されています。ストアド プロシージャが実行されるたびに、完了するまでに 15 ~ 30 分かかります。テーブルには 3 ~ 4 個の結合があります。ユーザーはそれについて頻繁に不平を言っています。インデックスは正しいです。パフォーマンスを向上させるために、分割されたビューを実装しました。MSDNの以下の記事を参考に解決策を実装しました

販売記録を年ごとに分割したところ、パフォーマンスが向上し、クエリ/ストアド プロシージャの実行に 3 ~ 5 分かかるようになりました。パフォーマンスをさらに向上させるために、販売記録を月ごとに分割します。4 年間のデータを維持しており、現在、売上データ用のテーブルが 48 近くあります (売上データを月ごとに分割した後)。これによりパフォーマンスが向上することを期待していました。しかし、それは起こっていません。クエリの実行が以前のもの (年ごとのデータ分割) よりもはるかに遅く、驚いています。また、クエリ プランを調べたところ、関連するテーブルのみをスキャンするのではなく、48 個の sales テーブルすべてに対してインデックス スキャンを実行していることがわかりました。たとえば、期間19-NOV-2012とのストア プロシージャを照会する場合、2 つのテーブル と20-DEC-2012のみを考慮する必要があります。NOV-2012DEC-2012. ただし、48 個のテーブルすべてを考慮しています。だから私の質問は:

  1. 関連するテーブルのみを考慮するのではなく、すべてのテーブルを考慮するのはなぜですか。たとえば、上記の例ではNOV-2012DEC-2012

  2. 年ごとのロジック (販売レコードを年ごとに分割) が月ごとのロジック (販売レコードを月ごとに分割) よりも優れている理由

以下は、分割ビューのコードです。
例 年 その他の年は省略します。

    SELECT * FROM tbl_Sales_Jan2010
UNION ALL
SELECT * FROM tbl_Sales_Feb2010
UNION ALL
SELECT * FROM tbl_Sales_Mar2010
UNION ALL
SELECT * FROM tbl_Sales_Apr2010
UNION ALL
SELECT * FROM tbl_Sales_May2010
UNION ALL
SELECT * FROM tbl_Sales_Jun2010
UNION ALL
SELECT * FROM tbl_Sales_Jul2010
UNION ALL
SELECT * FROM tbl_Sales_Aug2010
UNION ALL
SELECT * FROM tbl_Sales_Sep2010
UNION ALL
SELECT * FROM tbl_Sales_Oct2010
UNION ALL
SELECT * FROM tbl_Sales_Nov2010
UNION ALL
SELECT * FROM tbl_Sales_Dec2010

以下はテーブル構造です。

CREATE TABLE [dbo].[tbl_Sales_Jan2010](
    [SalesID] [numeric](10, 0) NOT NULL,
    [StoreNumber] [char](3) NOT NULL,
    [SomeColumn1] [varchar](15) NOT NULL,
    [Quantity] [int] NOT NULL,
    [SalePrice] [numeric](18, 2) NOT NULL,
    [SaleDate] [datetime] NOT NULL,
    [DeptID] [int] NOT NULL,
    [CatCode] [char](3) NOT NULL,
    [AuditDate] [datetime] NOT NULL CONSTRAINT [DF_tbl_Sales_Jan2010_EditDate]  DEFAULT (getdate()),
    [SomeColumn2] [varchar](15) NULL,
    [SaleMonthYear] [int] NULL CONSTRAINT [DF__tbl_Sales__SaleY__Jan2010]  DEFAULT (12010),
    [SaleDateInIntFormat] [int] NULL,
 CONSTRAINT [PK_tbl_Sales_Jan2010] PRIMARY KEY CLUSTERED 
(
    [SalesID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[tbl_Sales_Jan2010]  WITH CHECK ADD CHECK  (([SaleMonthYear] = 12010))

以下はクエリです

SELECT     SUM(C.Quantity) as total
    FROM         Productdatabase.dbo.tbl_Product A , Productdatabase.dbo.tbl_Product_Category B, XDatabase.dbo.vw_Sales_Test C, tbl_Store D
    WHERE     A.ProductID = B.ProductID AND B.CategoryID = @CateID
    AND C.SomeColumn = A.PRoductCode
    AND D.StoreCode = C.StoreNumber
    AND D.country = @country
    AND D.status = 0
    And C.SaleMonthYear between @BeginMonthYear and @EndMonthYear               
    AND C.SalDate between @FromSaleDate and @ToSaleDate     
4

2 に答える 2

3

パーティショニングを設定した人は、自分が何をしているのかを本当に考えていませんでした。パーティショニング (SQL Server の機能) を使用しないことに加えて、おそらくコストがかかります...

SELECT * FROM tbl_Sales_Jan2010

Union に WHERE 条件を追加すると、クエリ アナライザーは、where 句が正しくないために関連性のないテーブルを除外できます。すなわち追加:

(([SaleMonthYear] = 12010

すぐそこに。

次に、他の問題を修正します。本当。ポイントは:

データベース (SQL Server 2000 SP4) には、膨大な量のレコードを持つ 3 ~ 4 個のテーブルがあります。テーブルの 1 つには、2,500 万を超えるレコードがあります。

笑わせてください。2500万は小さくも小さくもありませんが、「ヒュー」とは何ですか?つまり、1 日に数億行を追加し、データを 2 年間保持するテーブルを操作しました。2500 万は、ミッドレンジ サーバーが簡単に処理できるものです。ハードウェアが悪い(つまり悪いという意味です)か、実際に他のことが起こっていることをお勧めします。

次のような設計上の問題:

[SaleMonthYear]

これは存在すべきではありません - それは SaleYearMonth であるべきなので、今は効率的に実行できない範囲テスト (201005 から 201008 の間) を行うことができます。

これはばかげています。これは、ここで利益を完全に失う数字だからです。

Whenever a stored procedure is executed it takes 15-30 minutes to complete

ここではっきりさせてください。そのような状況に適したミッドレンジのハードウェア (つまり、適切なサーバー、32 ~ 64 GB の RAM、12 ~ 24 個の高速ディスク) では、これに 15 ~ 30 分かかることはありません。あなたがそこに書いたコードではありません。

ロックの輻輳 (アプリケーションの設計が悪い) やサーバーが他のもので過負荷になっている場合 (アプリケーションの設計が悪い/管理が悪い) がある場合を除きます。そのようなクエリは、適切なインデックスを使用して、1 分未満で返されることを期待しています。

とにかく、パーティショニングは多くのチェックを高速に排除することで機能します-また、/ほとんどがあなたのケースでは削除の最適化です(テーブルを削除するだけで、deleteステートメントでハードインデックスの更新を行う必要はありません)。ただし、あなたがそれを実装した方法は、MS sasysが行うべき方法ではなく、ロジックが行うべきであると言う方法でもなく、パーティションがクエリに統合されていないため、結果が得られません。

テーブルとクエリを見ると、すべてのテーブルをチェックする必要があります。

于 2013-01-15T11:28:39.760 に答える
1

あなたが引用したのとまったく同じMSDNの記事から:

分割ビューが正しい結果を返すために CHECK 制約は必要ありません。ただし、CHECK 制約が定義されていない場合、クエリ オプティマイザーは、分割列の検索条件をカバーするテーブルだけでなく、すべてのテーブルを検索する必要があります。CHECK 制約がない場合、ビューは UNION ALL を使用する他のビューと同じように動作します。クエリ オプティマイザーは、さまざまなテーブルに格納されている値について推測することはできません。また、ビュー定義に含まれるテーブルの検索をスキップすることもできません。

あなたの質問では、2012 年 11 月 19 日から 2012 年 12 月 20 日までの日付範囲を持つクエリを指定しています。それはSaleDate列に含まれる値だと思いますが、制約はSaleMonthYear列にあります。

定義された制約は正しいですか? また、質問を投稿していただけますか?

ラージ

于 2013-01-15T10:30:49.387 に答える