sql >> データベース >  >> RDS >> Database

高度なSQL:CROSSAPPLYおよびOUTERAPLY

    この記事では、「APPLY」演算子とそのバリエーション(CROSSAPPLYとOUTERAPPLY)と、それらの使用方法の例について説明します。

    特に、次のことを学びます。

    • CROSSAPPLYとJOIN句の違い
    • SQLクエリの出力をテーブル評価関数と結合する方法
    • 動的管理ビューと動的管理機能を照会してパフォーマンスの問題を特定する方法。

    APPLY条項とは

    MicrosoftはSQLServer2005でAPPLY演算子を導入しました。APPLY演算子は、2つのテーブルを結合できるという点でT-SQL JOIN句に似ています。たとえば、外部テーブルと内部テーブルを結合できます。 APPLY演算子は、一方の側に、もう一方の側にあるテーブルの各行について評価するテーブル評価式がある場合に適したオプションです。したがって、右側のテーブルは、左側のテーブルの各行に対して処理されます。左側のテーブルが最初に評価され、次に右側のテーブルが左側のテーブルの各行に対して評価されて、最終的な結果セットが生成されます。最終的な結果セットには、両方のテーブルのすべての列が含まれます。

    APPLY演算子には2つのバリエーションがあります:

    • クロスアプライ
    • 外部適用

    クロスアプライ

    CROSSAPPLYはINNERJOINに似ていますが、テーブル評価関数をSQLテーブルと結合するためにも使用できます。 CROSS APPLYの最終出力は、テーブル評価関数の出力とSQLテーブルの間で一致するレコードで構成されます。

    外部適用

    OUTERAPPLYはLEFTJOINに似ていますが、テーブルで評価された関数をSQLテーブルと結合する機能があります。 OUTER APPLYの最終出力には、右側のテーブルまたはテーブル値関数のレコードと一致しない場合でも、左側のテーブルまたはテーブル評価関数のすべてのレコードが含まれます。

    それでは、両方のバリエーションを例を挙げて説明しましょう。

    使用例

    デモセットアップの準備

    デモのセットアップを準備するには、「DemoDatabase」と呼ばれるデータベースに「Employees」および「Department」という名前のテーブルを作成する必要があります。これを行うには、次のコードを実行します。

     USE DEMODATABASE GO CREATE TABLE [DBO]。[EMPLOYEES]([EMPLOYEENAME] [VARCHAR](MAX)NULL、[BIRTHDATE] [DATETIME] NULL、[JOBTITLE] [VARCHAR](150)NULL、[EMAILID] [ VARCHAR](100)NULL、[PHONENUMBER] [VARCHAR](20)NULL、[HIREDATE] [DATETIME] NULL、[DEPARTMENTID] [INT] NULL)GO CREATE TABLE [DBO]。[DEPARTMENT]([DEPARTMENTID] INT IDENTITY (1、1)、[DEPARTMENTNAME] [VARCHAR](MAX)NULL)GO 

    次に、ダミーデータを両方のテーブルに挿入します。次のスクリプトは、「従業員」にデータを挿入します s 」表:

    [タイトルを展開=”完全なクエリ 「]

     INSERT [DBO]。[EMPLOYEES]([EMPLOYEENAME]、[BIRTHDATE]、[JOBTITLE]、[EMAILID]、[PHONENUMBER]、[HIREDATE]、[DEPARTMENTID])VALUES(N'KENJSÁNCHEZ'、CAST (N'1969-01-29T00:00:00.000'AS DATETIME)、N'最高経営責任者'、N'[email protected]'、N'697-555-0142'、CAST(N'2009-01- 14T00:00:00.000'AS DATETIME)、1)、(N'TERRI LEE DUFFY'、CAST(N'1971-08-01T00:00:00.000'AS DATETIME)、N'VICE PRESIDENT OF ENGINEERING'、N'例@ sqldat.com'、N'819-555-0175'、CAST(N'2008-01-31T00:00:00.000'AS DATETIME)、NULL)、(N'ROBERTO TAMBURELLO'、CAST(N'1974-11 -12T00:00:00.000'AS DATETIME)、N'ENGINEERING MANAGER'、N'[email protected]'、N'212-555-0187'、CAST(N'2007-11-11T00:00:00.000' AS DATETIME)、NULL)、(N'ROB WALTERS'、CAST(N'1974-12-23T00:00:00.000' AS DATETIME)、N ' SENIOR TOOL DESIGNER'、N'[email protected]'、N'612-555-0100'、CAST(N'2007-12-05T00:00:00.000' AS DATETIME)、NULL)、(N'GAIL A ERICKSON '、CAST(N'1952-09-27T00:00:00.000' AS DATETIME)、N'DESIGN ENGINEER'、N'[email protected]'、N'849-555-0139'、CAST(N'2008- 01-06T00:00:00.000'AS DATETIME)、NULL)、(N'JOSSEF H GOLDBERG'、CAST(N'1959-03-11T00:00:00.000'AS DATETIME)、N'DESIGN ENGINEER'、N'例@ sqldat.com'、N'122-555-0189'、CAST(N'2008-01-24T00:00:00.000'AS DATETIME)、NULL)、(N'DYLAN A MILLER'、CAST(N'1987- 02-24T00:00:00.000'AS DATETIME)、N'研究開発マネージャー'、N'[email protected]'、N'181-555-0156'、CAST(N'2009-02-08T00:00: 00.000'AS DATETIME)、3)、(N'DIANE L MARGHEIM'、CAST(N'1986-06-05T00:00:00.000' AS DATETIME)、N'研究開発エンジニア'、 N'[email protected]'、N'815-555-0138'、CAST(N'2008-12-29T00:00:00.000' AS DATETIME)、3)、(N'GIGI N MATTHEW'、CAST(N '1979-01-21T00:00:00.000' AS DATETIME)、N'研究開発エンジニア'、N'[email protected]'、N'185-555-0186'、CAST(N'2009-01-16T00 :00:00.000'AS DATETIME)、3)、(N' MICHAEL RAHEEM'、CAST(N'1984-11-30T00:00:00.000' AS DATETIME)、N'研究開発マネージャー'、N'example @ sqldat .com'、N'330-555-2568'、CAST(N'2009-05-03T00:00:00.000'AS DATETIME)、3)

    [/エキスパンド]

    部門」にデータを追加するには 」テーブルで、次のスクリプトを実行します。

     INSERT [DBO]。[DEPARTMENT]([DEPARTMENTID]、[DEPARTMENTNAME])VALUES(1、N'IT')、(2、N'TECHNICAL')、(3、N'RESEARCH AND DEVELOPMENT')

    次に、データを確認するために、以下に示すコードを実行します。

     SELECT [EMPLOYEENAME]、[BIRTHDATE]、[JOBTITLE]、[EMAILID]、[PHONENUMBER]、[HIREDATE]、[DEPARTMENTID] FROM [EMPLOYEES] GOSELECT [DEPARTMENTID]、[DEPARTMENTNAME] FROM [DEPARTMENT] GO 

    必要な出力は次のとおりです。

    テーブル評価関数の作成とテスト

    すでに述べたように、「 CROSS APPLY 」および「外部適用 」は、SQLテーブルをテーブル評価関数と結合するために使用されます。これを示すために、「 getEmployeeData」という名前のテーブル評価関数を作成しましょう。 。」この関数は、 DepartmentIDの値を使用します 列を入力パラメータとして使用し、対応する部門からすべての従業員を返します。

    関数を作成するには、次のスクリプトを実行します。

     CREATE FUNCTION Getemployeesbydepartment(@DEPARTMENTID INT)RETURNS @EMPLOYEES TABLE(EMPLOYEENAME VARCHAR(MAX)、BIRTHDATE DATETIME、JOBTITLE VARCHAR(150)、EMAILID VARCHAR(100)、PHONENUMBER VARCHAR(20)、HIREDATE DATETIME、DEPARTMENTID VARCHAR ))AS BEGIN INSERT INTO @EMPLOYEES SELECT A.EMPLOYEENAME、A.BIRTHDATE、A.JOBTITLE、A.EMAILID、A.PHONENUMBER、A.HIREDATE、A.DEPARTMENTID FROM [EMPLOYEES] A WHERE A.DEPARTMENTID =@DEPARTMENTID RETURN END 

    ここで、関数をテストするために、「 1」を渡します。 」を「departmentID」として 」から「Getemployeesbydepartment " 働き。これを行うには、以下のスクリプトを実行します。

     DEMODATABASEGOSELECT EMPLOYEENAME、BIRTHDATE、JOBTITLE、EMAILID、PHONENUMBER、HIREDATE、DEPARTMENTIDFROM GETEMPLOYEESBYDEPARTMENT(1)を使用

    出力は次のようになります。

    CROSSAPPLYを使用してテーブル評価関数を使用してテーブルを結合する

    それでは、「 Getemployeesbydepartment」を使用してEmployeesテーブルを結合してみましょう。 ” CROSS APPLYを使用したテーブル評価関数 。前述したように、 CROSS APPLY 演算子はJoin句に似ています。 「従業員」からのすべてのレコードにデータが入力されます 「Getemployeesbydepartment」の出力に一致する行がある「」テーブル 」。

    次のスクリプトを実行します:

     SELECT A. [EMPLOYEENAME]、A. [BIRTHDATE]、A. [JOBTITLE]、A. [EMAILID]、A. [PHONENUMBER]、A. [HIREDATE]、B. [DEPARTMENTNAME] FROM DEPARTMENT B CROSS APPLY GETEMPLOYEESBYDEPARTMENT(B.DEPARTMENTID)A 

    出力は次のようになります。

    OUTERAPPLYを使用してテーブル評価関数を使用してテーブルを結合する

    それでは、「 Getemployeesbydepartment」を使用してEmployeesテーブルを結合してみましょう。 ” OUTER APPLYを使用したテーブル評価関数 。前に述べたように、外部適用 演算子は「OUTERJOIN」に似ています 」句。 「従業員」からのすべてのレコードにデータを入力します 」テーブルと「Getemployeesbydepartment」の出力 」機能。

    次のスクリプトを実行します:

     SELECT A. [EMPLOYEENAME]、A. [BIRTHDATE]、A. [JOBTITLE]、A. [EMAILID]、A. [PHONENUMBER]、A. [HIREDATE]、B. [DEPARTMENTNAME] FROM DEPARTMENT B OUTER APPLY GETEMPLOYEESBYDEPARTMENT(B.DEPARTMENTID)A 

    結果として表示される出力は次のとおりです。

    動的管理機能とビューを使用してパフォーマンスの問題を特定する

    別の例を示しましょう。ここでは、動的管理関数と動的管理ビューを使用して、クエリプランと対応するクエリテキストを取得する方法を説明します。

    デモンストレーションの目的で、「 SmokeTestResults」という名前のテーブルを作成しました 「DemoDatabase」の」。アプリケーションのスモークテストの結果が含まれています。誤って、開発者がSQLクエリを実行して、「 SmokeTestResults」からのデータを入力するとします。 」フィルターを追加せずに、データベースのパフォーマンスを大幅に低下させます。

    DBAとして、リソースを大量に消費するクエリを特定する必要があります。これを行うには、「 sys.dm_exec_requests」を使用します 」ビューと「sys.dm_exec_sql_text 」機能。

    Sys.dm_exec_requests 」は動的な管理ビューであり、リソースを消費するクエリを識別するために使用できる次の重要な詳細を提供します。

    1. セッションID
    2. CPU時間
    3. 待機タイプ
    4. データベースID
    5. 読み取り(物理)
    6. 書き込み(物理)
    7. 論理読み取り
    8. SQLハンドル
    9. プランハンドル
    10. クエリステータス
    11. コマンド
    12. トランザクションID

    sys.dm_exec_sql_text 」は、SQLハンドルを受け入れる動的管理関数です。 入力パラメータとして、次の詳細を提供します:

    1. データベースID
    2. オブジェクトID
    3. 暗号化されています
    4. SQLクエリテキスト

    それでは、次のクエリを実行して、ASAPデータベースにストレスを発生させましょう。次のクエリを実行します:

     USE ASAP GO SELECT TSID、USERID、EXECUTIONID、EX_RESULTFILE、EX_TESTDATAFILE、EX_ZIPFILE、EX_STARTTIME、EX_ENDTIME、EX_REMARKSFROM[ASAP]。[DBO]。[SMOKETESTRESULTS]

    SQL ServerはセッションID「66」を割り当て、クエリの実行を開始します。次の画像を参照してください:

    ここで、問題のトラブルシューティングを行うには、データベースID、論理読み取り、が必要です。 SQL クエリ、コマンド、セッションID、待機タイプ およびSQLハンドル 。前述したように、データベースID、論理読み取り、コマンド、セッションID、待機タイプを取得できます。 およびSQLハンドル 「sys.dm_exec_requests」から。 SQLクエリを取得するには 、「sys.dm_exec_sql_text。」を使用する必要があります 」これは動的な管理機能であるため、「 sys.dm_exec_requests」に参加する必要があります 」と「sys.dm_exec_sql_text 」CROSSAPPLYを使用します。

    [新しいクエリエディタ]ウィンドウで、次のクエリを実行します。

     SELECT B.TEXT、A.WAIT_TYPE、A.LAST_WAIT_TYPE、A.COMMAND、A.SESSION_ID、CPU_TIME、A.BLOCKING_SESSION_ID、A.LOGICAL_READS FROM SYS.DM_EXEC_REQUESTS A CROSS APPLY SYS.DM_EXEC_SQL_TEXT(A.SQL_HANDLE) / pre> 

    次の出力が生成されます。

    上のスクリーンショットでわかるように、クエリはパフォーマンスの問題を特定するために必要なすべての情報を返しました。

    ここで、クエリテキストに加えて、問題のクエリを実行するために使用された実行プランを取得します。これを行うには、「sys.dm_exec_query_plan」を使用します 機能。

    sys.dm_exec_query_plan 」は、プランハンドルを受け入れる動的管理機能です。 入力パラメータとして、次の詳細を提供します:

    1. データベースID
    2. オブジェクトID
    3. 暗号化されています
    4. XML形式のSQLクエリプラン

    クエリ実行プランにデータを入力するには、CROSSAPPLYを使用して「sys.dm_exec_requests」に参加する必要があります 」および「sys.dm_exec_query_plan。

    [新しいクエリエディタ]ウィンドウを開き、次のクエリを実行します。

     SELECT B.TEXT、A.WAIT_TYPE、A.LAST_WAIT_TYPE、A.COMMAND、A.SESSION_ID、CPU_TIME、A.BLOCKING_SESSION_ID、A.LOGICAL_READS、C.QUERY_PLAN FROM SYS.DM_EXEC_REQUESTS A CROSS APPLY SYS.DM_EXEC_SQL_TEXT SQL_HANDLE)B CROSS APPLY SYS.DM_EXEC_QUERY_PLAN(A.PLAN_HANDLE)C 

    出力は次のようになります。

    ご覧のとおり、クエリプランはデフォルトでXML形式で生成されます。グラフィカル表現として開くには、 query_planのXML出力をクリックします。 上の画像に示すような列。 XML出力をクリックすると、次の画像に示すように、実行プランが新しいウィンドウで開きます。

    動的管理ビューと関数を使用して、高度に断片化されたインデックスを持つテーブルのリストを取得する

    もう1つの例を見てみましょう。特定のデータベースで50%以上の断片化があるインデックスを持つテーブルのリストを取得したいと思います。これらのテーブルを取得するには、「 sys.dm_db_index_physical_stats」を使用する必要があります 」ビューと「sys.tables 」機能。

    Sys.tables 」は、特定のデータベース上のテーブルのリストを作成する動的な管理ビューです。

    sys.dm_db_index_physical_stats 」は、次の入力パラメータを受け入れる動的管理機能です。

    1. データベースID
    2. オブジェクトID
    3. インデックスID
    4. パーティション番号
    5. モード

    指定されたインデックスの物理ステータスに関する詳細情報を返します。

    ここで、断片化されたインデックスのリストを作成するには、「 sys.dm_db_index_physical_stats」に参加する必要があります。 」および「sys.tables 」CROSSAPPLYを使用します。次のクエリを実行します:

     SELECT TABLES.NAME、INDEXSTATISTICS.ALLOC_UNIT_TYPE_DESC、CONVERT(NUMERIC(10、2)、INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT)AS PERCENTAGEFRAGMENTATION、INDEXSTATISTICS.PAGE_COUNT FROM SYS.TABLES AS TABLES CROSS APPLY SYS.DM_DB_INDEX 、NULL、NULL、NULL)AS INDEXSTATISTICS WHERE INDEXSTATISTICS.DATABASE_ID =DB_ID()AND AVG_FRAGMENTATION_IN_PERCENT> =50 ORDER BY INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT DESC 

    クエリは次の出力を生成する必要があります:

    概要

    この記事では、APPLY演算子、そのバリエーション(CROSSAPPLYとOUTERAPLY)、およびその動作について説明しました。また、動的管理ビューと動的管理関数を使用してSQLパフォーマンスの問題を特定するためにそれらを使用する方法も確認しました。


    1. SQLServerのメンテナンスプランを使用してバックアップとメンテナンスのジョブを自動化する

    2. make_timestamptz()がPostgreSQLでどのように機能するか

    3. sqlite:合計時間を追加する方法hh:mm:ssここで、列のデータ型はDATETIMEですか?

    4. Pythondatetime.datetimeオブジェクトをMySQLに挿入する