1

データベースに関して言えば、私はほとんどばかです。あまり問題なく、やりたいことを行うためのクエリを書くことができますが、パフォーマンスの問題に遭遇したとき、何をすべきか本当にわかりません。受け取った。

私は3つのテーブルを持っています:

明細書

  • Bill_Id - BIGINT - 主キー
  • 請求日 - DATE

BillDetail

  • BillDetail_Id - BIGINT - 主キー
  • Bill_Id - BIGINT - Bill の外部キー、インデックス付き
  • BillDetailType_Id - INT - 索引付けされた BillDetailType の外部キー
  • お金をチャージ

BillDetailType

  • BillDetailType_Id - INT - 主キー
  • タイプ名 - NVARCHAR(20)

各 Bill には複数の BillDetails があり、基本的には Bill の個々の項目です。すべての BillDetail には BillDetailType があり、これは請求項目の種類 (電気、インターネット、税金など) です。

次のようなビューも作成しました。

CREATE VIEW BillSubtotal
AS
SELECT b.*,
        (SELECT SUM(bd.Charge) FROM BillDetail AS bd INNER JOIN BillDetailType AS bdt ON bd.BillDetailType_Id = bdt.BillDetailType_Id
            WHERE (bdt.TypeName = 'Tax') AND (bd.Bill_Id = b.Bill_id)) AS Tax,
        (SELECT SUM(bd.Charge) FROM BillDetail AS bd INNER JOIN BillDetailType AS bdt ON bd.BillDetailType_Id = bdt.BillDetailType_Id
            WHERE (bdt.TypeName <> 'Tax') AND (bd.Bill_Id = b.Bill_id)) AS NonTaxTotal
        FROM Bill AS b

このビューの実行には、約 60000 Bills と 700000 BillDetails を持つ現在の開発データベースで約 14 秒かかります。26 の異なる BillDetailTypes があります。これが機能するようになったら、さらに小計を追加したいと思いますが、今のところはそれだけです。

今、私はこのような結合をしようとしています:

SELECT bs.BillDate, bs.Tax, bs.NonTaxTotal, bd.Charge, bdt.TypeName FROM
BillDetail bd
INNER JOIN BillSubtotal bs ON bs.Bill_Id = bd.Bill_Id
INNER JOIN BillDetailType bdt ON bdt.BillDetailType_Id = bd.BillDetailType_Id

特定の BillDetail が課税前請求書の何パーセントであるかなどを計算したいので、最終的には bd.Charge/bs.NonTaxTotal*100 のようなものになりますが、現時点では、このクエリの実行に 14時間かかりますそして、私はその理由を本当に理解していません。

INNER JOIN のいずれかを削除すると、クエリが劇的に高速化されます。

SELECT bs.BillDate, bs.Tax, bs.NonTaxTotal, bd.Charge FROM
BillDetail bd
INNER JOIN BillSubtotal bs ON bs.Bill_Id = bd.Bill_Id

実行には約 1.5 分かかります。

SELECT bd.Charge, bdt.TypeName FROM
BillDetail bd
INNER JOIN BillDetailType bdt ON bdt.BillDetailType_Id = bd.BillDetailType_Id

約12秒かかります。

どちらの結合も短時間で実行される理由はわかりませんが、結合を一緒に実行すると数時間かかります。たぶんそれは非常に明白なことですが、クエリがどのように評価されているのかよくわからないので、見逃しています。私は実行計画を見ましたが、そこから有用なものを得ることができず、行き詰まっています。結合の 1 つをサブクエリに移動するなど、さまざまな方法で切り替えを試みましたが、パフォーマンスが変わることはありませんでした。

助けてくれてありがとう。

4

2 に答える 2

3

ビューをまったく使用しないことをお勧めします。私は数年前にこれをたくさんやりましたが、長い間管理するのが難しくなりすぎました. いずれかのテーブルに列を追加する場合は、ビューを更新する必要があります。それはあまりにも面倒になります。そうは言っても、ビューにインデックスを追加できます。

また、 Group By戦略を使用することをお勧めします。私の経験では、これははるかに高速になる可能性があります。私はいくつかのケースでそれを使用しましたが、速度が大幅に改善されていることがわかりました。このようなもの:

 SELECT Bill_Id, 
     SUM(BillDetail.Charge), 
     CASE
         WHEN BillDetailType.TypeName = 'Tax'
             THEN 'Tax'
             ELSE 'Not Tax'
     END AS TypeName            
 FROM BillDetail
     INNER JOIN BillDetailType 
         ON BillDetail.BillDetailType_Id = BillDetailType.BillDetailType_Id
 GROUP BY Bill_Id, TypeName

ビューを作成するのではなく、このクエリを使用してそれに参加することができます。これにより、テーブル自体のインデックスが活用されます。

最後に、Sql Server Profiler ツールを使用して最終的なクエリを実行してみてください。

過去 7 年間に学んださまざまな手法を詳述したSQL Query Optimizationに関するブログ投稿があります。

于 2012-07-11T20:10:59.207 に答える
0

正確な実行計画を見ないとわかりませんが、ビューにいくつかのインデックスを作成する必要がある可能性は非常に高いです。クエリ オプティマイザーは、基になるテーブルのインデックスを必ずしも使用するとは限りません。特にビュー自体にインデックスを作成する必要がある場合があります。

実行計画のスクリーンショットがあると、分析がはるかに簡単になります。

MSDN の記事から: It is possible to create a unique clustered index on a view, as well as nonclustered indexes, to improve data access performance on the most complex queries by precomputing and materializing the view. **This is often particularly effective for aggregate views** in decision support or data warehouse environments.(強調は私のもの)。

于 2012-07-01T01:07:48.997 に答える