2016-11-08 7 views
1

SQL과 관련하여 나는 상대적으로 경험이 없습니다. 나는 CROSS APPLY을 사용하는 것이 아래의 SQL에서 가장 좋은 옵션인지 궁금합니다.CROSS가 가장 좋은 방법인가요 아니면 EXISTS 또는 하위 쿼리가있을 때 가능합니까?

나는 또한 작품을 복제한다고 생각합니다. 이것은 효과가 있고 몇 분이 걸리지 만 제 느낌은 더 잘할 수 있다는 것입니다.

내가보고있는 3 개의 주 테이블은 꽤 크고 각각 2 백만 행을보고 있습니다. 개별 insert 문은 각각 약 7 - 15K 행으로 되돌아갑니다.


DECLARE @Master TABLE 
    (
    heyno    NVARCHAR(12), 
    postcodestartdttm DATE, 
    postcodeenddttm DATE, 
    lzohistorypostcode NVARCHAR(25), 
    biactivitypostcode NVARCHAR(25), 
    activityenddttm DATE 
); 

INSERT INTO @Master 
SELECT p.pasid, 
     par.startdttm, 
     par.enddttm, 
     pa.postcode AS LZOHistoryPostcode, 
     t.postcode AS BIActivityPostcode, 
     t.admitdate 
FROM HEALTHBI.DBO.[lzo_patientaddressrole] AS par 
     INNER JOIN HEALTHBI.DBO.[lzo_patientaddress] AS pa 
       ON par.[addressoid] = pa.[oid] 
        AND pa.[status] = 'A' 
     INNER JOIN HEALTHBI.DBO.lzo_patient AS p 
       ON par.identifyingoid = p.oid 
     --- 
     CROSS APPLY (SELECT i.admitdate, 
          i.postcode 
        FROM HEALTHBI_VIEWS.DBO.ip_admission i 
        WHERE i.patientoid = p.oid 
          AND i.admitdate > par.startdttm 
          AND i.admitdate >= '01 APRIL 2010' 
          AND i.admitdate < ISNULL(par.enddttm, '31-dec-4712') 
          AND par.[status] = 'A' 
          AND par.[identifyingtype] = 'Patient' 
          AND par.[rotypcode] = 'CC_USUALADD' 
          AND pa.[adtypcode] = 'Address' 
          AND pa.postcode <> i.postcode) AS t 

INSERT INTO @Master 
SELECT p.pasid, 
     par.startdttm, 
     par.enddttm, 
     pa.postcode AS LZOHistoryPostcode, 
     t.postcode AS BIActivityPostcode, 
     t.apptstartdate 
FROM HEALTHBI.DBO.[lzo_patientaddressrole] AS par 
     INNER JOIN HEALTHBI.DBO.[lzo_patientaddress] AS pa 
       ON par.[addressoid] = pa.[oid] 
        AND pa.[status] = 'A' 
     INNER JOIN HEALTHBI.DBO.lzo_patient AS p 
       ON par.identifyingoid = p.oid 
     CROSS APPLY (SELECT i.apptstartdate, 
          i.postcode 
        FROM HEALTHBI_VIEWS.DBO.op_appointment i 
        WHERE i.patientoid = p.oid 
          AND i.apptstartdate > par.startdttm 
          AND i.apptstartdate >= '01 APRIL 2010' 
          AND i.apptstartdate < ISNULL(par.enddttm, '31-dec-4712') 
          AND par.[status] = 'A' 
          AND par.[identifyingtype] = 'Patient' 
          AND par.[rotypcode] = 'CC_USUALADD' 
          AND pa.[adtypcode] = 'Address' 
          AND pa.postcode <> i.postcode) AS t 

INSERT INTO @Master 
SELECT p.pasid, 
     par.startdttm, 
     par.enddttm, 
     pa.postcode AS LZOHistoryPostcode, 
     t.postcode AS BIActivityPostcode, 
     t.attenddate 
FROM HEALTHBI.DBO.[lzo_patientaddressrole] AS par 
     INNER JOIN HEALTHBI.DBO.[lzo_patientaddress] AS pa 
       ON par.[addressoid] = pa.[oid] 
        AND pa.[status] = 'A' 
     INNER JOIN HEALTHBI.DBO.lzo_patient AS p 
       ON par.identifyingoid = p.oid 
     CROSS APPLY (SELECT i.attenddate, 
          i.postcode 
        FROM HEALTHBI_VIEWS.DBO.ed_attendance i 
        WHERE i.patientoid = p.oid 
          AND i.attenddate > par.startdttm 
          AND i.attenddate >= '01 APRIL 2010' 
          AND i.attenddate < ISNULL(par.enddttm, '31-dec-4712') 
          AND par.[status] = 'A' 
          AND par.[identifyingtype] = 'Patient' 
          AND par.[rotypcode] = 'CC_USUALADD' 
          AND pa.[adtypcode] = 'Address' 
          AND pa.postcode <> i.postcode) AS t 

SELECT m.heyno, 
     m.lzohistorypostcode, 
     m.biactivitypostcode, 
     d.startofweek 
FROM @Master m 
     INNER JOIN HEALTHBI_VIEWS.DBO.date_reference AS d 
       ON m.activityenddttm = d.datevalue 
GROUP BY m.heyno, 
      m.lzohistorypostcode, 
      m.biactivitypostcode, 
      d.startofweek 
ORDER BY m.heyno 
+0

왜 'LEFT JOIN'입니까? – Ben

+0

주 결합이 PK에 대해 1-1이기 때문입니다. – Simon

+0

그래서? 그게 무슨 상관이야? – Ben

답변

-1

당신은 CROSS APPLY가 사용하지 않습니다. 이것은 테이블 값 함수와 함께 사용하기위한 것이고, 커서와 같이 조금씩 작동합니다. 한 번에 하나의 레코드가 설정 작업보다 훨씬 느립니다.

아래와 같이 OUTER JOIN을 사용하려고합니다. 데이터를 더 잘 이해하지 않고서는 제대로 이해하기는 어렵지만 각 환자마다 여러 입학 날짜와 우편 번호가 표시되므로 ip_addmission보기에서 반환하는 내용에 따라 중복되는 부분이있을 수 있습니다. 원하는 경우 GROUP BY를 사용하여 최신 입학 날짜 만 반환 할 수 있습니다.

또한 테이블 검색을 유발할 수 있으므로 WHERE 절에서 함수를 사용하지 마십시오. ISNULL을 아래의 OR 식으로 바꿨습니다.

SELECT p.pasid, 
     par.startdttm, 
     par.enddttm, 
     pa.postcode AS LZOHistoryPostcode, 
     i.postcode AS BIActivityPostcode, 
     i.admitdate 
FROM HEALTHBI.DBO.[lzo_patientaddressrole] AS par 
     INNER JOIN HEALTHBI.DBO.[lzo_patientaddress] AS pa 
       ON par.[addressoid] = pa.[oid] 
        AND pa.[status] = 'A' 
     INNER JOIN HEALTHBI.DBO.lzo_patient AS p 
       ON par.identifyingoid = p.oid 
     --- 
     LEFT OUTER JOIN HEALTHBI_VIEWS.DBO.ip_admission i 
     ON i.patientoid = p.oid 

WHERE i.admitdate > par.startdttm 
          AND i.admitdate >= '01 APRIL 2010' 
          AND (i.admitdate < par.enddttm OR par.enddttm IS NULL) 
          AND par.[status] = 'A' 
          AND par.[identifyingtype] = 'Patient' 
          AND par.[rotypcode] = 'CC_USUALADD' 
          AND pa.[adtypcode] = 'Address' 
          AND pa.postcode <> i.postcode; 
+0

당신은 이것에 대해 틀린 말입니다 : "교차 적용은 테이블 값 기능과 함께 사용하기위한 것이고 커서와 같이 한 번에 하나의 레코드처럼 작동합니다. 이는 설정 작업보다 훨씬 느립니다." APPLY는 JOIN만큼 빨리 작동합니다. –