0

このクエリを実行している7600万行を超えるreadingsというテーブルがあります。

declare @tunnel_id int = 13
SELECT TOP 1 local_time, recorded_time
FROM readings
WHERE tunnel_id = @tunnel_id 
ORDER BY id DESC

id 列は bigint であり、主キーとして設定され、クラスター化されたインデックスがあり、tunnel_id フィールドにもインデックスがあります。

私が試している20個の異なるtunnel_idのうち約16個で、うまく機能し、1秒もかからずに戻ります。ただし、最後の 4 つほどでは、クエリに 40 秒かかり、数十万回の読み取りが使用されます。

クエリをこれに変更してみました:

SELECT TOP (1) local_time, recorded_time
FROM readings
where id = (
    SELECT TOP 1 id
    FROM readings
    WHERE tunnel_id = 13
    ORDER BY id DESC
)

これもまた、いくつかの tunnel_id でのみ遅くなります。私をさらに困惑させているのは、内部選択が遅いIDに対してすばやく実行され、サブクエリの代わりに最大IDをハードコーディングすると、それもすばやく実行されることです。

このクエリのパフォーマンスが低下している原因は何ですか?

コメントの編集:

Tunnel_id は一意ではなく、各トンネルには数百万の行があります。これはSql Server 2012で実行されています。

高速実行と低速実行の両方からの実際の実行計画を含めましたが、それらは同一です。

速い: SQL高速実行計画.

遅い:

SQL高速実行計画.

しかし、ご覧のとおり、最初の実行は 1 秒未満で実行され、2 番目の実行には 51 秒かかります。

4

3 に答える 3

1

このプランは基本的に、クラスター化されたインデックス全体を最初から最後までスキャンし、tunnel_id = @tunnel_id の最初の行を探します。

私の推測では、「遅い」トンネルにはクラスター化インデックスの先頭に行がないため、より多くの行をスキャンする必要があります。

この非クラスター化インデックスは速度を向上させるはずです。

CREATE NONCLUSTERED INDEX [IX_FOO] ON [readings]
(
    tunnel_id, 
    ID 
)
INCLUDE 
(
    local_time, 
    recorded_time
)

これにより、tunnel_id の既存のインデックスが置き換えられる可能性があります。

于 2013-07-09T20:51:38.610 に答える
0

tunnel_id インデックスを使用するようにヒントできることがわかりました。

declare @tunnel_id int = 13
SELECT TOP 1 local_time, recorded_time
FROM readings
WITH (INDEX(idx_tunnel_id))
WHERE tunnel_id = @tunnel_id 
ORDER BY id DESC

これは期待どおりに機能し、1 秒以内に戻ります。

于 2013-08-19T20:45:34.403 に答える