3

900 万件のレコードを含むHISTORYテーブルがあります。作成された年ごと、月ごとのレコードを見つける必要があります。クエリ番号 1 を使用していましたが、数回タイムアウトしました。

SELECT 
    year(created) as year, 
    MONTHNAME(created) as month, 
    count(*) as ymcount  
FROM 
    HISTORY 
GROUP BY 
    year(created), MONTHNAME(created);

を追加することにしましwhere year(created)た。今回は、クエリの実行に 30 分かかりました (はい、非常に時間がかかります)。

SELECT 
    year(created) as year, 
    MONTHNAME(created) as month, 
    count(*) as ymcount  
FROM 
    HISTORY 
WHERE 
    year(created) = 2010
GROUP BY  
    year(created), MONTHNAME(created) ;

タイムスタンプ列にインデックスを追加することを計画してcreatedいましたが、その前に意見が必要です (このような巨大なテーブルのインデックス作成には時間がかかるため)。

created(timestamp)年関数が列で使用されていることを考えると、列にインデックスを追加するとパフォーマンスが向上しますか?

4

5 に答える 5

4

完全なテーブルスキャン、インデックス、またはインデックスなしを実行する必要があるようにクエリを作成しているため、インデックスは実際には役に立ちません。次の形式にwhereなるように句を作成する必要があります。

where field op constant

fieldもちろん、あなたの分野はどこですか。opis= <= => <> between inなどであり、constant は、直接定数 、42または一度実行して結果をキャッシュできる操作 のいずれかgetdate()です。

このような:

where created >= DateFromParts( @year, 1, 1 )
  and created < DateFromParts( @year + 1, 1, 1 )

このDateFromParts関数は、クエリの期間中有効な値を生成します。がインデックス化されている場合created、オプティマイザーは正確な日付の開始位置を正確に検索し、範囲内の最後の日付がいつ処理されて停止できるかを知ることができます。他のどこでも保持できます-節year(created)からそれを取り除くだけです.where

これは sargability と呼ばれ、あらゆる種類の優れた情報をググることができます。

PSこれはSql Server形式ですが、使用しているDBMSで「指定された年の初め」と「指定された年の後の年の初め」を計算できるはずです。

于 2014-06-21T01:38:38.740 に答える
1

読み取る行数を絞り込むのに役立つ場合は、インデックスが使用されます。

テーブルをまったく読み取らない場合にも使用されます。これは、クエリで参照されるすべての列がインデックスに含まれている場合です。

あなたの場合、参照される唯一の列はcreatedであるため、この列にインデックスを追加すると、必要な読み取りを減らし、クエリの全体的な実行時間を改善するのに役立ちます。ただし、createdテーブル内の唯一の列である場合、インデックスは最初のクエリで何も変更しません。これは、読み取るページ数が減らないためです。

大きなテーブルでも、インデックスが違いを生むかどうかをテストできます。行の一部のみを新しいテーブルにコピーし、新しいテーブルの実行計画をインデックスの有無で比較できます。

insert into testhistory
select *
from history
fetch first 100000 rows only
于 2014-06-22T12:34:36.937 に答える
1

カレンダー テーブルと呼ばれるものが必要です(特定の例では SQL Server を使用していますが、ソリューションは適応可能である必要があります)。次に、そこに多くのインデックスが必要です (書き込みが少なく、これが分析用のプライマリ ディメンション テーブルであるため)。

次のような最小限のカレンダー テーブルがあると仮定します。

CREATE TABLE Calendar (isoDate     DATE,
                       dayOfMonth  INTEGER,
                       month       INTEGER,
                       year        INTEGER);

dayOfMonth... [ , month, year, ]のインデックスをisoDate使用すると、クエリは次のように書き直すことができます。

SELECT Calendar.year, Calendar.month,
       COUNT(*) AS ymCount
FROM Calendar
JOIN History
  ON History.created >= Calendar.isoDate
     AND History.created < Calendar.isoDate + 1 MONTH
WHERE Calendar.dayOfMonth = 1
GROUP BY Calendar.year, Calendar.month

WHERE Calendar.dayOfMonth = 1自動的に結果を年間 12 件に制限しています。範囲の開始は、インデックス (SARGable データが与えられた場合) で簡単に配置され、範囲の終了も同様です (はい、列で計算を行うと、一般にインデックスが不適格になります... 計算が使用される側で。オプティマイザは非常にスマートで、範囲の開始/終了を含む仮想中間テーブルを生成します)。

したがって、クエリに対するインデックスベース (およびおそらくインデックスのみ) アクセス。範囲クエリに使用できる、インデックス付きのディメンション テーブルを愛することを学びましょう (カレンダー テーブルは最も便利なテーブルの 1 つです)。

于 2014-06-22T22:43:19.117 に答える
0

タグに基づいて SQL Server を使用していると仮定します。

はい、インデックスはクエリを高速化します。

「作成された」列のみをインデックスのキーとして使用し、履歴テーブルから追加の列を含めないことをお勧めします。これらの列は使用されず、必要以上の読み取りが発生するだけだからです。

もちろん、INSERT、UPDATE、DELETE アクティビティが多いテーブルにインデックスを作成する場合は注意が必要です。新しいインデックスを作成すると、これらのアクションをテーブルで実行するとコストが高くなるからです。

于 2014-06-20T21:03:20.417 に答える