2016-11-08 9 views
1

Я относительно неопытен, когда дело доходит до SQL. Я задаюсь вопросом, является ли использование CROSS APPLY лучшим вариантом в SQL ниже?Является ли CROSS APPLY лучшим способом или, возможно, КОГДА СУЩЕСТВУЕТ или подзапрос?

Я также думаю, что дублирую работу. Это работает и занимает несколько минут, но я чувствую, что это можно сделать лучше.

Три основных таблицы, на которые я смотрю, довольно большие и сами по себе, мы смотрим на пару миллионов строк каждый. Отдельные инструкции вставки оттягиваются вокруг 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

, потому что основные соединения 1-1 против ПК. – Simon

+0

Итак? Что это имеет значение? – Ben

ответ

-1

Вы не хотите использовать CROSS ОТНОСИТЬСЯ. Это предназначено для использования со значениями значений таблиц и работает немного как курсор, по одной записи за раз, что намного медленнее, чем заданные операции.

Я бы постарался использовать ВНУТРЕННУЮ РАБОТУ, а не как ниже. Трудно понять это, не понимая данные лучше, но кажется, что для каждого пациента вы получите несколько дат приема и почтовые коды, поэтому у вас может быть некоторое дублирование в зависимости от того, какое представление 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

Вы ошибаетесь в этом: «Cross apply предназначен для использования со значениями значений таблицы, и он работает немного как курсор, по одной записи за раз, что намного медленнее, чем заданные операции». APPLY работает так же быстро, как JOIN. –