10

現在、次のステートメントを実行しています

select * into adhoc..san_savedi from dps_san..savedi_record

痛々しいほど長い時間がかかっています。どこまで進んでいるのかを確認したいので、これを実行しました。

select count(*) from adhoc..san_savedi with (nolock)

それはタイムリーに何も返さなかったので、私はこれをしました:

select top 1 * from adhoc..san_savedi with (nolock)

それでも無期限に実行されるようです。count(*) に時間がかかる可能性があるレコードが数百万ある場合は理解できましたが、nolock を指定したことを考えると、トップ 1 レコードを選択してもすぐに返されない理由がわかりません。

完全開示の名の下に、dps_san はリンク サーバー経由で odbc 接続からプルするビューです。一番上の行を返せない理由に影響を与えるとは思いませんが、間違っている場合に備えてそこに捨てるだけです。

それで、何がそのステートメントの実行を妨げているのか知りたいですか?

編集:

上で述べたように、はい dps_san..savedi_record はビューです。これが何をするかです:

select * from DPS_SAN..root.SAVEDI_RECORD

これはエイリアスにすぎず、グループ化/ソートなどを行わないため、ここに問題があるとは思いませんが、間違っている場合は教えてください.

4

4 に答える 4

11

SELECTを使用したクエリNOLOCKは実際にはロックを取得しませんがSCH-S、テーブルに (スキーマの安定性) ロックが必要です (また、ヒープであるため、ロックも取得しhobtます)。

さらに、開始する前に、 SQL Server はステートメントのプランをコンパイルする必要があります。これには、テーブルをロックアウトするSELECTことも必要です。SCH-S

長時間実行されるトランザクションがテーブルを作成すると、ステートメントが完了するまでSELECT ... INTO互換性のないロックが保持されます。SCH-M

これは、ブロック中に覗き込むことで確認できますsys.dm_os_waiting_tasks

1つの接続で次のことを試したとき

BEGIN TRAN

SELECT *
INTO NewT
FROM master..spt_values

/*Remember to rollback/commit this later*/

そして実行します(または単に推定実行計画を表示しようとします)

SELECT *
FROM NewT
WITH (NOLOCK)

すぐに読み取りクエリがブロックされました。

SELECT wait_type,
       resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id = <spid_of_waiting_task>

待機タイプが実際にSCH_Sあり、ブロックしているリソースを示しますSCH-M

wait_type        resource_description
---------------- -------------------------------------------------------------------------------------------------------------------------------
LCK_M_SCH_S      objectlock lockPartition=0 objid=461960722 subresource=FULL dbid=1 id=lock4a8a540 mode=Sch-M associatedObjectId=461960722
于 2012-06-08T20:58:29.570 に答える
2

ロックがない可能性が非常に高いです... dps_san..savedi_record がビューの場合、インデックスを使用せずにテーブルにアクセスしている可能性があるか、数百万をソートしている可能性があるため、実行に時間がかかる可能性があります記録の、または何らかの理由で。そうすると、クエリは、たとえ単純なトップやカウントであっても、そのビューを実行できる速さしかありません。

于 2012-06-08T20:42:56.023 に答える
2

ここで考慮すべきいくつかの問題。dps_san..savedi_record はビューですか? その場合、データを取得するのに非常に長い時間がかかっている可能性があります。select into他に考えられるのは、構文を使用して一時テーブルを作成しようとしているということですが、これは悪い考えです。select * into ...構文は、選択中に tempdb をロックします。

その構文を使用してテーブルを作成している場合は、回避策があります。where 1=0最初に、最初のステートメントの最後にスローして、テーブルを作成します。

select * into ... from ... where 1=0

これにより、最初にテーブルが作成されます(これは迅速です)。これによりinsert into、テーブルが現在存在するため(クエリ中に tempdb をロックするペナルティなしで)作成できます。

于 2012-06-08T20:45:03.620 に答える
2

session_idを実行している を見つけますselect into:

SELECT r.session_id, r.blocking_session_id, r.wait_type, r.wait_time
  FROM sys.dm_exec_requests AS r
  CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
  WHERE t.[text] LIKE '%select%into%adhoc..san_savedi%';

これにより、別のセッションが選択をブロックしているかどうか、または問題を引き起こしている待機タイプがあるかどうかがわかります。

選択しようとしているセッションの別のウィンドウでプロセスを繰り返すことができます。Martin の言うことは正しいし、スキーマ ロックに関する私の以前のコメントは適切であると思います。

于 2012-06-08T21:00:42.977 に答える