5

新しいシステムを継承し、データを改善しようとしています。私はこの表を改善しようとしていますが、私の発見を理解できないようです。

私は次のテーブル構造を持っています:

CREATE TABLE [dbo].[Calls](
    [CallID] [varchar](8) NOT NULL PRIMARY KEY,
    [RecvdDate] [varchar](10) NOT NULL,
    [yr] [int] NOT NULL,
    [Mnth] [int] NOT NULL,
    [CallStatus] [varchar](50) NOT NULL,
    [Category] [varchar](100) NOT NULL,
    [QCall] [varchar](15) NOT NULL,
    [KOUNT] [int] NOT NULL)

このテーブルには、約22万件のレコードが含まれています。特定の日付よりも古い日付を持つすべてのレコードを返す必要があります。この場合、2009年12月1日。このクエリは約66kレコードを返し、実行には約4秒かかります。過去のシステムから、私がこれに取り組んできたのは高いようです。特に、テーブルにあるレコードの数を考えると。ですから、その時間を減らしたいと思います。

だから私はそれを下げるためのいくつかの良い方法は何でしょうか?テーブルに日付列を追加し、文字列dateを実際の日付列に変換してみました。次に、その日付列にインデックスを追加しましたが、時刻は同じままでした。レコードがそれほど多くないことを考えると、テーブルスキャンがどのように高速であるかはわかりますが、インデックスによってその時間が短縮される可能性があると思います。

また、月と年の列をクエリすることも検討しました。しかし、私はまだそれを試していません。また、可能であれば日付列から外したいと思います。しかし、そうでなければ私はそれを変えることができます。

どんな助けでも大歓迎です。

編集:これが私が実行しようとしているクエリであり、テーブルの速度をテストしています。私は通常列を出しますが、簡単にするために使用しました*:

SELECT *
FROM _FirstSlaLevel_Tickets_New
WHERE TicketRecvdDateTime >= '12/01/2009'

編集2:それで、私は、recvddateデータを含むが、varcharではなく日付として日付列を持つテーブルを作成しようとしたと述べました。これが、上記のクエリのTicketRecvdDateTime列です。このテーブルに対して実行している元のクエリは次のとおりです。

SELECT *
FROM Calls
WHERE CAST(RecvdDate AS DATE) >= '12/01/2009'
4

5 に答える 5

4

SQLServerでティッピングポイントと呼ばれるものに遭遇している可能性があります。列に適切なインデックスがある場合でも、返される予想行数があるしきい値(「転換点」)を超えると、SQLServerはテーブルスキャンを実行することを決定する場合があります。

あなたの例では、これはデータベースの行数の1/4を回しているためと思われます。以下はこれを説明する良い記事です:http://www.sqlskills.com/BLOGS/KIMBERLY/category/The-Tipping-Point.aspx

于 2010-11-29T19:06:39.797 に答える
4

SELECT *通常、パフォーマンスが低下します。

インデックスが無視されるか、クラスター化されたインデックスへのキー/ブックマークのルックアップが発生します。関係ありません:両方ともうまくいかない可能性があります。

たとえば、このクエリがあり、TicketRecvdDateTimeのインデックスにCallStatusが含まれている場合期待どおりに実行される可能性があります。これはカバーするでしょう

SELECT CallStatus
FROM _FirstSlaLevel_Tickets_New
WHERE TicketRecvdDateTime >= '12/01/2009'

これは、Randy Minderの答えに追加されます。キー/ブックマークのルックアップは、少数の行に対しては十分に安価である可能性がありますが、テーブルデータの大きなチャンクに対してはそうではありません。

于 2010-11-29T19:14:53.950 に答える
3

クエリは、インデックスなしの方が高速です(または、より正確には、indeXなしまたはなしで同じ速度です)。インデックスonは、のような式でRecvdDate常に無視されるためCAST(RecvdDate AS DATE) >= '12/01/2009'です。これは、関数を介して列を変換する必要があるため、SARG不可能な式です。このインデックスイベントが考慮されるためには、それに基づく式ではなく、インデックスが作成されている列でフィルタ基準を正確に表現する必要があります。これが最初のステップになります。

さらにステップがあります:

  • 日付のVARCHAR(10)列を削除し、適切なDATE列またはDATETIME列に置き換えます。文字列として日付や時刻を保存すると、問題が発生します。索引付けだけでなく、正確さのためにも。
  • 列に基づく範囲で頻繁にスキャンされるテーブル(ほとんどのコールログテーブルがそうであるように)は、その列によってクラスター化する必要があります。
  • と列が実際に必要になる可能性はほとんどありませんyrmnth本当に必要な場合は、おそらく計算列として必要です。

CREATE TABLE [dbo].[Calls](
    [CallID] [varchar](8) NOT NULL,
    [RecvdDate] [datetime](10) NOT NULL,
    [CallStatus] [varchar](50) NOT NULL,
    [Category] [varchar](100) NOT NULL,
    [QCall] [varchar](15) NOT NULL,
    [KOUNT] [int] NOT NULL,
    CONSTRAINT [PK_Calls_CallId] PRIMARY KEY NONCLUSTERED ([CallID]));

CREATE CLUSTERED INDEX cdxCalls ON Calls(RecvDate);

SELECT *
FROM Calls
WHERE RecvDate >= '12/01/2009';

もちろん、テーブルとインデックスの適切な構造は、更新のパフォーマンスやその他のクエリなど、関連するすべての要因を考慮して慎重に分析した結果である必要があります。インデックスの設計に含まれるすべてのトピックから始めることをお勧めします。

于 2010-11-29T19:47:01.120 に答える
0

クエリを変更できますか?必要な列が少ない場合は、SELECT句を変更して、返す列の数を減らすことができます。次に、を含む、参照されるすべての列を含むカバーインデックスを作成できますTicketRecvdDateTime

にインデックスを作成するTicketRecvdDateTimeこともできますが、@RandyMinderが説明する転換点を避けられない場合があります。ただし、小さいインデックス(テーブルスキャンよりも小さい)でのスキャンでは、返されるページが少なくなります。

于 2010-11-29T19:18:28.320 に答える
0

RecvdDateがあなたが話しているTicketRecvdDateTimeであると仮定します:

SQL Serverは、フィールドタイプがDATEの場合にのみ、日付を一重引用符で囲んで比較します。あなたのクエリはおそらくそれらをVARCHARとして比較しています。'99/99/0001'の行を追加して、下部に表示されるかどうかを確認してください。

その場合、クエリ結果は正しくありません。タイプをDATEに変更します。

VARCHARはインデックスを適切に作成しないことに注意してください。DATETIMEはインデックスを作成します。

クエリプランをチェックして、インデックスを使用しているかどうかを確認します。DBが使用可能なRAMと比較して小さい場合、DBは単にテーブルスキャンを実行し、すべてをメモリに保持する可能性があります。

編集:CAST / DATETIMEの編集を見て、VARCHARからの日付の解析は非常にコストのかかる操作であることを指摘しておきます。あなたはこれを22万回やっています。これにより、パフォーマンスが低下します。

また、インデックス付きフィールドをチェックしなくなりました。インデックスフィールドを含む式との比較では、インデックスは使用されません。

于 2010-11-29T19:18:46.693 に答える