6

主キー(autoinc bigint)を持つ35の列と、クラスター化されていない、一意でない3つのインデックス(それぞれが1つのint列にある)を持つ支払いのテーブルがあるとします。

テーブルの列には、2つの日時フィールドがあります。

  1. 支払期日 datetime NOT NULL

  2. 編集日 datetime NULL

テーブルには約120万行があります。edit_date column=nullを持つ行は約1000行のみです。9000行のedit_dateがnullでなく、payment_dateと等しくない他の行にはedit_date=payment_dateがあります

次のクエリを実行すると1

select top 1 *
from payments
where edit_date is not null and (payment_date=edit_date or payment_date<>edit_date)
order by payment_date desc

ここに画像の説明を入力してください

サーバーはそれを行うのに数秒かかります。しかし、クエリ2を実行すると:

select top 1 *
from payments
where edit_date is not null
order by payment_date desc

ここに画像の説明を入力してください

実行は、データベース'tempdb'のログファイルがいっぱいになります。データベースのトランザクションログをバックアップして、ログスペースを解放します。

*を特定の列に置き換える場合は、クエリ3を参照してください。

select top 1 payment_date
from payments
where edit_date is not null
order by payment_date desc

ここに画像の説明を入力してください

また、数秒で終了します。

魔法はどこにありますか?

編集 クエリ1を変更して、2番目のクエリとまったく同じ行数で動作するようにしました。それでも、クエリ2がtempdbを埋めている間、1秒で戻ります。

答え 私はインデックスを追加するためのアドバイスに従い、両方の日付フィールドに対してこれを行いました-すべてが期待どおりに迅速に機能し始めました。ただし、問題は、この正確な状況でSQLサーバーが同様のクエリ(クエリ1とクエリ2)で異なる動作をする理由です。サーバー最適化のロジックを理解したかったのです。両方のクエリが同様にtempdbを使用した場合は同意しますが、使用しませんでした。

結局、私は最初の答えとしてマークを付けます。そこでは、私の問題の必須の症状が見られ、これを回避する方法についての最初の考えもあります(つまり、不注意)。

4

2 に答える 2

5

通常、ディスク容量が不足している場合、またはデータベースの拡張に不当に低い最大サイズを設定している場合、tempdbはいっぱいになります。多くの人は、tempdbは#tempテーブルにのみ使用されると考えています。実際には、単一の一時テーブルを作成しなくても、tempdbを簡単に埋めることができます。tempdbがいっぱいになる可能性のある他のいくつかのシナリオ:

  • SQL Serverに割り当てられているよりも多くのメモリを必要とする並べ替えは、tempdbでの作業を強制されます。
  • 並べ替えにtempdbに割り当てたよりも多くのスペースが必要な場合、上記のエラーのいずれかが発生します。
  • DBCC CheckDB('any database')は、tempdbで作業を実行します。大規模なデータベースでは、かなりのスペースを消費する可能性があります。
  • 'Sort intempdb'オプションが設定されたDBCCDBREINDEXまたは同様のDBCCコマンドも、tempdbをいっぱいにする可能性があります。
  • ユニオン、order by / group by、デカルト結合、外部結合、カーソル、一時テーブル、テーブル変数、およびハッシュを含む大規模な結果セットでは、多くの場合、tempdbの支援が必要になる場合があります。
  • コミットされずにロールバックされないままのトランザクションは、tempdbでオブジェクトを孤立させたままにする可能性があります。
  • オプション「一時ストアード・プロシージャーの作成」が設定されたODBC DSNを使用すると、接続の存続期間中、オブジェクトをそこに残すことができます。

    tempdbGOを使用する

        SELECT name 
            FROM tempdb..sysobjects 
    
        SELECT OBJECT_NAME(id), rowcnt 
            FROM tempdb..sysindexes 
            WHERE OBJECT_NAME(id) LIKE '#%' 
            ORDER BY rowcnt DESC
    

行数が多いほど、値はスペースを消費している最大の一時テーブルを示している可能性があります。

短期的な修正

DBCC OPENTRAN -- or DBCC OPENTRAN('tempdb')
DBCC INPUTBUFFER(<number>)
KILL <number>

長期予防

-- SQL Server 7.0, should show 'trunc. log on chkpt.' 
-- or 'recovery=SIMPLE' as part of status column: 

EXEC sp_helpdb 'tempdb' 

-- SQL Server 2000, should yield 'SIMPLE': 

SELECT DATABASEPROPERTYEX('tempdb', 'recovery')
ALTER DATABASE tempdb SET RECOVERY SIMPLE

参照:https ://web.archive.org/web/20080509095429/http://sqlserver2000.databases.aspfaq.com:80 / why-is-tempdb-full-and-how-can-i-prevent-this- from-happening.html
その他の参照:http ://social.msdn.microsoft.com/Forums/is/transactsql/thread/af493428-2062-4445-88e4-07ac65fedb76

于 2012-08-09T04:54:20.357 に答える
5

これは、実行計画の特定のステップが、tempdb特定の特定のsorts大量joinsのデータへの書き込みをトリガーする可能性があるために発生しています。

大量の列を持つテーブルをソートしているため、SQL は、関連付けられたデータなしで一時データベースで単独でソートを実行するのはおかしいと判断します。その場合、基になるテーブルで非常に非効率なブックマーク ルックアップを実行する必要があります。

次の規則に従います。

  1. 必要なデータのみを選択してみてください
  2. 大量の行をソートするクレイジーなクエリを実行する必要がある場合は、適切なサイズの tempdb を使用することをお勧めします。
于 2012-08-09T04:08:19.613 に答える