質問

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

次のテーブル構造があります。

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)

このテーブルには約220kのレコードがあります。日付が特定の日付よりも大きいすべてのレコードを返す必要があります。この場合、2009年12月1日。このクエリは約66kのレコードを返し、実行には約4秒かかります。過去のシステムから、私はこれに取り組んできました。特に、テーブルに記録が少ないことを考えると。だから私はその時間を倒したいと思います。

それで、私はそれを倒すための良い方法は何だろうと思っていますか?日付列をテーブルに追加し、文字列日付を実際の日付列に変換しようとしました。次に、その日付列にインデックスを追加しましたが、時間は同じままでした。それほど多くのレコードがないことを考えると、テーブルスキャンがどのように高速になるかを見ることができますが、インデックスがその時間を減らすことができると思います。

また、月と年の列を照会するだけで検討しました。しかし、私はまだ試していません。そして、可能であれば、日付列からそれを維持したいと思います。しかし、そうでない場合は、変更できます。

どんな助けも感謝しています。

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

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'
役に立ちましたか?

解決

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

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

他のヒント

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

インデックスが無視されるか、クラスター化されたインデックスのキー/ブックマークの検索が行われます。関係ありません:両方ともひどく実行できます。

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

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

これは、Randy Minderの答えに加えてです。キー/ブックマークの検索は、少数の行に十分に安くなるかもしれませんが、テーブルデータの大部分ではありません。

あなたのクエリは、インデックス(または、より正確には、インデックス付きで同じ速度)とインデックスがあるため、より正確には同じ速度です) RecvdDate 意思 いつも のような表現で無視されます CAST(RecvdDate AS DATE) >= '12/01/2009'. 。これは、列を関数に変換する必要があるため、掘り不可能な式ではありません。このインデックスのために 考慮すべきイベント, 、フィルター基準を表現する必要があります まさに 列にはインデックス化されている列には、それに基づいた式ではありません。これが最初のステップです。

その他のステップがあります:

  • 日付のVarchar(10)列を取り除き、適切な日付または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';

もちろん、テーブルとインデックスの適切な構造は、慎重な分析の結果である必要があります。 すべて 更新パフォーマンス、その他のクエリなどを含む関係する要因。 インデックスの設計.

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

インデックスを作成する場合があります TicketRecvdDateTime, 、しかし、@Randy Minderが議論する転換点を避けないかもしれません。ただし、小さいインデックス(テーブルスキャンよりも小さい)でスキャンすると、より少ないページが返されます。

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

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

その場合、クエリの結果が正しくありません。これまでのタイプを変更します。

Varcharは適切にインデックスを付けていないことに注意してください、DateTimeはそうであることに注意してください。

クエリ計画を確認して、インデックスを使用しているかどうかを確認してください。 DBが利用可能なRAMと比較して小さい場合、テーブルスキャンしてすべてをメモリに保持することができます。

編集:キャスト/DateTimeの編集を見ると、Varcharからの日付を解析することは非常に高価な操作であることを指摘させてください。あなたはこれを220Kをやっています。これはパフォーマンスを殺します。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top