web-dev-qa-db-ja.com

CPU時間と経過時間の計算に関する混乱

私はすでに別のオンラインフォーラムで検索しましたが、これについて明確な答えはありません。

問題は、経過時間よりも4倍長いCPU時間を持つクエリがあることです。また、経過時間がCPU時間より長いクエリもあります。なぜそうなのか理解できません。光を当てていただけませんか。どちらの場合でも実際に何が起こりますか?

たとえば、クエリのCPU時間は4000ミリ秒で、経過時間は1000ミリ秒で、1つのクエリの経過時間は2ミリ秒で、CPU時間は0ミリ秒です。

次の投稿によると:

https://stackoverflow.com/questions/6419312/sql-server-query-tuning-why-cpu-time-is-higher-than-elapsed-time-are-they-rel

cPU時間の増加と経過時間の減少は、SQLサーバーによるハイパースレッディングまたはマルチコアの使用によるものですが、それに関する信頼できる情報を見つけることができません。別の混乱は逆の場合です。 CPU時間が0ミリ秒であるのに、経過時間がたとえば4ミリ秒である可能性はありますか?

これに関する詳細な回答をいただければ幸いです。

4
Ehsan Sajjad

クエリのCPU時間の方が経過時間より多い場合は、並列実行されるゾーンがクエリに含まれていたことを意味します。経過時間に対するCPU時間の比率は、クエリで使用可能なCPUの数、クエリが待機した時間と待機時間(一部はサーバーのワークロードに依存)、クエリがどれだけ効率的に実行できるかなど、多くの要因に依存します並列処理の利点。最後のポイント参照の例 アムダールの法則

たとえば、プログラムがシングルプロセッサコアを使用して20時間を必要とし、実行に1時間かかるプログラムの特定の部分は並列化できない場合、残りの19時間(p = 0.95)の実行時間は並列化できます。このプログラムの並列実行に費やされるプロセッサーの数に関係なく、最小実行時間はそのクリティカルな1時間より短くなることはできません。

多くのクエリには、並列に実行されるゾーンと直列に実行されるゾーンがあります。ほとんどの作業が並列ゾーンで行われ、作業がスケジューラ間で均等に分散されている場合、CPU時間と経過時間の比率が高くなる可能性があります。

以下は、SQL Serverで非常に効率的に並列化できるクエリのちょっとした例です。最初に、私がテストしているマシンには4つのコアがあり、それらすべてがクエリで使用できることに注意してください。タスクマネージャから:

task monitor

SQL Serverから:

SELECT cpu_count -- result of 4
FROM sys.dm_os_sys_info;

次に、1つの一時テーブルに100行、もう1つに100k行を配置します。

CREATE TABLE #OUTER_TABLE (ID INT NOT NULL);

-- insert 100 integers from 1 - 100
INSERT INTO #OUTER_TABLE
SELECT N
FROM dbo.getNums(100);

CREATE TABLE #INNER_TABLE (COL VARCHAR(8000));

-- insert 100000 rows
INSERT INTO #INNER_TABLE
SELECT REPLICATE('Z', 800)
FROM dbo.getNums(100000);

SET STATISTICS TIME ON;

これが私がテストするクエリです:

SELECT ot.ID, it.COL
FROM 
(
    SELECT TOP 100 ID
    FROM #OUTER_TABLE
) ot
CROSS APPLY (
    SELECT MAX(COL) COL
    FROM #INNER_TABLE
    WHERE COL <> CAST(ot.ID AS VARCHAR(8000))
) it
 -- TF 8649 is only used for demonstration purposes and should not be used in production
OPTION (MAXDOP 4, QUERYTRACEON 8649);

少し混乱しているので、それを見ていきましょう。クエリがテーブル内のデータに基づいて、#OUTER_TABLEからの100行すべてと#INNER_TABLEからの値を返します。ただし、この情報をクエリオプティマイザーで利用できるようにしていないため、期待どおりの結果を得るには多くの作業が必要になります。全体的にクエリはばかげていますが、重要なのは クエリの実行 の方法です。これがスクリーンショットです:

actual query plan

質問に関係がないので、このようにクエリを作成した理由をスキップします。ただし、#OUTER_TABLEの100行が4つのスレッドに分割され、スレッドごとに25行あることに注意してください。各スレッドは行ごとに#INNER_TABLEのフルスキャンを実行するため、4つのスレッドがそれぞれ25スキャンを実行します。ループの内側のクエリの一部は、予想どおりにほとんどすべての処理を実行します(外側の部分は100行をスキャンしますが、内側の部分は100 * 100000 = 10000000行をスキャンします)。

MAXDOP 4を使用して(4つのコアすべてを使用して)クエリを実行すると、SET STATISTICS TIME ONから次の結果が得られます。

SQL Server実行時間:

CPU時間= 24500ミリ秒、経過時間= 6357ミリ秒。

MAXDOP 2(2つのコアのみを使用)で実行すると、次の結果が得られます。

SQL Server実行時間:

CPU時間= 23422 ms、経過時間= 11864 ms。

MAXDOP 1(並列ではない)で実行すると、次の結果が得られます。

SQL Server実行時間:

CPU時間= 23313ミリ秒、経過時間= 23361ミリ秒。

ご覧のとおり、クエリは並列処理を非常に効率的に利用できます。実際のクエリのほとんどは、CPU時間と経過時間の比率が比較的高くありません(DOPを考慮した後)。

経過時間がCPU時間より長くなる場合の例として、SQL Server Management Studioの結果グリッドなどのクライアントに結果を送信するのにかかる時間を考慮してください。これらの結果を送信する時間は経過時間に含まれますが、CPU時間に大きく影響することはありません。サーバーがメモリまたはディスクから結果を読み取るために行う作業は、CPU時間と経過時間の両方に影響します。結果をクライアントに送信するために費やされる時間は、待機イベントの1つのタイプです(通常はASYNC_NETWORK_IO)。 多くの異なる理由 SQL Serverクエリが待機している可能性があり、それらすべてが同じようにCPU使用率に影響を与えるわけではない理由があります。

このクエリを実行するとします。

SELECT * FROM INNER_TABLE;

結果をクライアントに取得すると、CPU時間は94ミリ秒、経過時間は749ミリ秒になります。 sys.dm_exec_session_wait_stats を使用して、セッションの待機イベントを確認できます。

╔═══════════════════════╦═════════════════════╦══════════════╦══════════════════╦═════════════════════╗
║       wait_type       ║ waiting_tasks_count ║ wait_time_ms ║ max_wait_time_ms ║ signal_wait_time_ms ║
╠═══════════════════════╬═════════════════════╬══════════════╬══════════════════╬═════════════════════╣
║ ASYNC_NETWORK_IO      ║               19444 ║          662 ║               12 ║                  67 ║
║ MEMORY_ALLOCATION_EXT ║                  37 ║            0 ║                0 ║                   0 ║
╚═══════════════════════╩═════════════════════╩══════════════╩══════════════════╩═════════════════════╝

結果セットをクライアントに返さずに、別のセッションでクエリを実行することもできます。 1つのテストでは、これには47ミリ秒のCPU時間と60ミリ秒の経過時間がかかりました。以下は、他のクエリとはかなり異なる、そのクエリの待機セッションです。

╔═══════════════════════╦═════════════════════╦══════════════╦══════════════════╦═════════════════════╗
║       wait_type       ║ waiting_tasks_count ║ wait_time_ms ║ max_wait_time_ms ║ signal_wait_time_ms ║
╠═══════════════════════╬═════════════════════╬══════════════╬══════════════════╬═════════════════════╣
║ ASYNC_NETWORK_IO      ║                 185 ║            2 ║                0 ║                   1 ║
║ SOS_SCHEDULER_YIELD   ║                   7 ║            0 ║                0 ║                   0 ║
║ MEMORY_ALLOCATION_EXT ║                  40 ║            0 ║                0 ║                   0 ║
╚═══════════════════════╩═════════════════════╩══════════════╩══════════════════╩═════════════════════╝
7
Joe Obbish