1

我正在處理對錶單進行審計的查詢。有幾頁需要審覈。當表單填寫的答案被存儲在兩個表中的以下方式:極其緩慢的查詢,其中包含多個子查詢SQL Server 2008 R2

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將答案存儲在一行中,因此每次訪問只有一行。表3是一樣的,每個訪問ID只有一行。

我的查詢通過收集存儲在表中的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人表示,這個問題是使用的情況下回答聲明和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 ,所以如果我不使用它,人們可以完成所有其他事情,但如果不是那個特定的項目,那麼他們將被排除在最終結果集之外。

如果我需要澄清,請讓我知道。

** QUERY實際執行計劃XML ** query exec actual xml

謝謝

+0

請在某處上傳實際(未估計)執行計劃的XML。 –

+0

會這麼做,它需要大約30分鐘左右才能運行,以顯示兩個需要子查詢的問題。 –

+0

在這種情況下,在嘗試用'CREATE TABLE#T1(VISIT_ID VARCHAR(20)PRIMARY KEY)'替換表變量'@ T1'之前。這可能有幫助,但至少不應妨礙。 –

回答

4

smsmir.obsv一種觀點認爲UNION -s一155569000行的表和15375000行之一。

執行計劃顯示這些表被掃描了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 
+0

我現在就試試這個,由於某種原因,我從來沒有收到通知,當我從課程上課回家後,我發佈了一個答案,現在開始運行並將發佈結果。 –

+0

好吧,這工作真的很快(相對於我的,0:4:56:00),但是當一條記錄沒有結果時,我得到一個空值爲VISIT ID而不是像123456789這樣的實際ID。這是非常重要的我們想要調查爲什麼事情沒有完成,特別是在存在0的情況下獲得ID號。所以,如果我們能夠解決這個問題,那麼這將得到明顯的答案,你會得到積分。這裏是新的實際執行XML https://app.box.com/s/stlhmh8j5m8tmu7yopds –

+1

@MCP_infiltrator - 哦,是的。 SELECT SELECT#T1.VISIT_ID' –

0

你不必再次打表,你已經有了數據。彙總它。

DECLARE @SD DATETIME 
DECLARE @ED DATETIME 

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

DECLARE @T1 TABLE (
    VISIT_ID VARCHAR(20)) 

INSERT INTO @T1 
SELECT A.PtNo_Num 
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 

SELECT DISTINCT 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], 
      max(CASE 
       WHEN form_usage = 'Admission' THEN 1 
       ELSE 0 
      END)    AS [ADMIT ASSESSMENT DONE], 
      max(CASE 
       WHEN form_usage = 'Admission' AND obsv_cd_ext_name = 'Admission consent signed:' THEN 1 
       ELSE 0 
      END)   AS [ADMIT CONSENT SIGNED?] 
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 
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