1

フォームの監査を行うクエリに取り組んでいます。監査する質問のページが数ページあります。フォームに入力すると、回答は次の方法で 2 つのテーブルに保存されます。

Table 1: smsmir.obsv OBS
EPISODE NO | FORM USAGE | QUEST      | ANSWER | ...
123456789  | ADMISSION  | QUESTION 1 | YES    | ...
123456789  | ADMISSION  | QUESTION 2 | 150    | ...
...

Table 2: smsdss.QOC_vst_summ QOC
EPISODE NO | HT IND | WT IND | ADV DIR | ...
123456789  |    1   |   1    |     0   | ...
...

表 1:smsmir.obsv OBS情報をベクトルに格納するため、質問ごとに別の行があります。表 2:smsdss.QOC_vst_summ QOC回答を 1 行に格納するため、1 回の訪問につき 1 行しかありません。表 3 も同じで、訪問 ID ごとに 1 つの行しかありません。

私のクエリは、テーブルに格納されたものを収集VISIT IDSすることから始まり、いくつかの質問に答えるために次のセットに渡されます。この別のテーブルから訪問 ID を取得する理由は、そこに訪問の開始日と終了日が保存されているためです。そのテーブルは次のようになります。

Table 3: smsdss.BMH_PLM_PtAcct_V PAV
EPISODE NO | ADM DATE   | ...
123456789  | 2013-08-01 | ...
...

私が得る私の望ましい出力は、次のようなものです:

EPISODE NO | QUESTION 1  | QUESTION 2 | HT IND | WT IND | ADV DIR | ...
123456789  |   1         | 1          |    1   |    1   |    0    | ...
...

上記の表で、1 は case ステートメントを使用して質問に回答されたことを表し、0 は回答されていないことを示します。クエリは書き直され、現在は正しい結果が生成されていますが、40 レコードを取得するのに 53 分 36 秒かかっており、非常に低速です。クエリは現在未完成で 7 列しか返されていないため、これを拡張して合計 65 列にする必要があります。

サブクエリがある理由は、回答がベクトルに格納されているためです。各行は質問と回答ですが、回答と質問を列に表示したいので、サブクエリを実行します。これを高速化するより良い方法はありますか?

クエリは次のとおりです。

-- THIS QUERY WILL PERFORM AN AUDIT OF THE ADMISSION ASSESSMENT AND
-- OTHER REQUIRED QUESTIONS BY NURSING INFORMATICS
-----------------------------------------------------------------------
-- VARIABLE DECLARATION AND INITIALIZATION. BY DECLARING A START AND
-- END DATE A USER CAN SIMPLY CHANGE THOSE PARAMETERS AND AUDIT ALL 
-- INPATIENT ADMISSION ASSESSMENTS FOR THAT TIME PERIOD
DECLARE @SD DATETIME
DECLARE @ED DATETIME

SET @SD = '2013-08-01'
SET @ED = '2013-08-01'

-- QUERY 1
-- THIS QUERY CREATES A TABLE THAT WILL HOUSE ALL VISIT ID NUMBERS THAT
-- ARE GOING TO BE INCLUDED INSIDE OF THE ADMISSION ASSESSMENT AUDIT
-- TABLE DECLARATION ##################################################
DECLARE @T1 TABLE (
  VISIT_ID VARCHAR(20))

-- ####################################################################
-- THESE ARE THE ITEMS THAT ARE GOING TO BE INSERTED INTO THE TABLE
INSERT INTO @T1
-- COLUMN SELECTION
SELECT A.PtNo_Num
-- DB(S) USED
FROM   (SELECT DISTINCT PTNO_NUM
        FROM   smsdss.BMH_PLM_PtAcct_V
        WHERE  Adm_Date BETWEEN @SD AND @ED
               AND Plm_Pt_Acct_Type = 'I') A

--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
-----------------------------------------------------------------------
-- QUERY TWO. THIS QUERY WILL TAKE THE VISIT ID'S FROM QUERY 1 AND RUN
-- THEM THROUGH A SET OF RULES TO DECIDE WHEATHER OR NOT THE ADDMISISON
-- ASSESSMENT WAS PROPERLY DONE
-----------------------------------------------------------------------
-- COLUMN SELECTION
SELECT DISTINCT OBS.episode_no  AS [VISIT ID]
                -- CASE STATEMENT, IF PREFERRED LANGUAGE IS NOT 'NULL' THEN CONSIDER
                -- THIS COMPLETE AND SCORE 1 ELSE CONSIDER INCOMPLETE AND SCORE 0
                ,
                CASE
                  WHEN QOC.prim_lng IS NOT NULL THEN 1
                  ELSE 0
                END             AS [PREF LANG COMPLETE?],
                QOC.ht_chtd_ind AS [HT IND],
                QOC.wt_chtd_ind AS [WT IND],
                QOC.adv_dir_ind AS [ADV DIRECTIVE]
                -- A SEPERATE SELECT STATEMENT IS USED HERE BECAUSE RESULTS OF THE
                -- ADMISSION CONSENT ARE STORED IN A VECTOR, SO IT IS NECESSARY TO
                -- MAKE A SELECTION FROM THAT LIST, HERE A VALUE OF 1 = YES AND 
                -- 0 = NO
                ,
                CASE
                  WHEN OBS.episode_no NOT IN (SELECT episode_no
                                              FROM   smsmir.obsv
                                              WHERE  form_usage = 'Admission') THEN 0
                  ELSE 1
                END             AS [ADMIT ASSESSMENT DONE],
                CASE
                  WHEN OBS.episode_no NOT IN (SELECT episode_no
                                              FROM   smsmir.obsv
                                              WHERE  form_usage = 'Admission'
                                                     AND obsv_cd_ext_name = 'Admission consent signed:') THEN 0
                  ELSE 1
                END             AS [ADMIT CONSENT SIGNED?]
-- DB(S) USED ---------------------------------------------------------
FROM   smsmir.obsv OBS
       JOIN smsdss.QOC_vst_summ QOC
         ON OBS.episode_no = QOC.episode_no
       JOIN @T1 T1
         ON OBS.episode_no = T1.VISIT_ID
-- FILTERS ------------------------------------------------------------
WHERE  T1.VISIT_ID = OBS.episode_no
GROUP  BY OBS.episode_no,
          QOC.prim_lng,
          QOC.ht_chtd_ind,
          QOC.wt_chtd_ind,
          QOC.adv_dir_ind,
          OBS.obsv_cd_ext_name
--#####################################################################
-- END REPORT ...[]...[]...[]

私が句を使用していることに気付くでしょうNOT IN。その理由は、質問が尋ねられなかったり、答えられなかったりした場合、記録さえも存在NULLしないためです。その特定のアイテムではない場合、それらは最終結果セットから除外されます。

明確にする必要がある場合は、お知らせください。

** クエリ 実際の実行計画 XML ** クエリ exec 実際の xml

ありがとうございました

4

2 に答える 2

4

smsmir.obsvUNION-sa 155,569,000 行のテーブルと 15,375,000 行のビューです。

実行計画は、これらのテーブルが 42 回スキャンされることを示しています。

これの大部分は、ネストされたループの不適切な選択を意味する、テーブル変数のデフォルトの不十分なカーディナリティ推定が原因です。#tempテーブルに置き換えると、その問題が解決するはずです。

またPIVOT、個々のサブクエリの代わりに手法を使用すると、これをさらに減らすことができます。不足しているインデックスを追加するという点で適用できる追加の最適化があるかもしれませんが、これを試してタイミングと実行計画を教えてもらえますか?

DECLARE @SD DATETIME = '2013-08-01';
DECLARE @ED DATETIME = '2013-08-01';

CREATE TABLE #T1
  (
     VISIT_ID VARCHAR(20) UNIQUE CLUSTERED
  )

INSERT INTO #T1
SELECT DISTINCT PTNO_NUM
FROM   smsdss.BMH_PLM_PtAcct_V
WHERE  Adm_Date BETWEEN @SD AND @ED
       AND Plm_Pt_Acct_Type = 'I'
OPTION (RECOMPILE);

WITH OBS
     AS (SELECT episode_no,
                MAX(CASE
                      WHEN form_usage = 'Admission' THEN 1
                    END) AS [ADMIT ASSESSMENT DONE],
                MAX(CASE
                      WHEN form_usage = 'Admission'
                           AND obsv_cd_ext_name = 'Admission consent signed:' THEN 1
                    END) AS [ADMIT CONSENT SIGNED?]
         FROM   smsmir.obsv
         WHERE form_usage = 'Admission' 
         GROUP  BY episode_no)
SELECT OBS.episode_no                         AS [VISIT ID],
       CASE
         WHEN QOC.prim_lng IS NOT NULL THEN 1
         ELSE 0
       END                                    AS [PREF LANG COMPLETE?],
       QOC.ht_chtd_ind                        AS [HT IND],
       QOC.wt_chtd_ind                        AS [WT IND],
       QOC.adv_dir_ind                        AS [ADV DIRECTIVE],
       ISNULL(OBS.[ADMIT ASSESSMENT DONE], 0) AS [ADMIT ASSESSMENT DONE],
       ISNULL(OBS.[ADMIT CONSENT SIGNED?], 0) AS [ADMIT CONSENT SIGNED?]
FROM   smsdss.QOC_vst_summ QOC
       JOIN #T1
         ON #T1.VISIT_ID = QOC.episode_no
       LEFT JOIN OBS
         ON OBS.episode_no = QOC.episode_no 

DROP TABLE #T1
于 2013-08-28T20:22:52.917 に答える