Необходимо ускорить результаты этого оператора SQL. Любой совет? - PullRequest
3 голосов
/ 31 марта 2010

У меня есть следующий оператор SQL, который нуждается в некотором ускорении. Проблема в том, что мне нужно искать в двух полях, где каждое из них вызывает несколько подвыборов. Есть ли способ соединить два поля вместе, чтобы я вызывал суб-выбор только один раз?

SELECT billyr, billno, propacct, vinid, taxpaid, duedate, datepif, propdesc
FROM trcdba.billspaid
WHERE date(datepif) > '01/06/2009'
AND date(datepif) <= '01/06/2010'
AND custno in
 (select custno from cwdba.txpytaxid where taxpayerno in
  (select taxpayerno from cwdba.txpyaccts where accountno in
   (select accountno from rtadba.reasacct where controlno = 1234567)))
OR custno2 in
 (select custno from cwdba.txpytaxid where taxpayerno in
  (select taxpayerno from cwdba.txpyaccts where accountno in
   (select accountno from rtadba.reasacct where controlno = 1234567)))

Ответы [ 4 ]

13 голосов
/ 31 марта 2010

Я бы использовал соединения вместо встроенных подзапросов.

6 голосов
/ 31 марта 2010

при использовании функции в столбце:

date(datepif) > '01/06/2009'
AND date(datepif) <= '01/06/2010'

индекс НЕ будет использоваться. Попробуйте что-то вроде этого

datepif > someconversionhere('01/06/2009')
AND datepif <= someconversionhere('01/06/2010')

Используйте также внутренние соединения. В вопросе нет никакой информации, указывающей размер таблицы или наличие индекса, или нет, так что это предположение, и оно должно работать лучше всего, если в billspaid намного больше строк для диапазона дат по сравнению со строками, соответствующими присоединяющимся таблицам для r.controlno = 1234567, что, как я подозреваю, имеет место:

SELECT 
    COALESCE(b1.billyr,b2.billyr)           AS billyr
        ,COALESCE(b1.billno,b2.billno)      AS billno
        ,COALESCE(b1.propacct,b2.propacct)  AS propacct
        ,COALESCE(b1.vinid,b2.vinid)        AS vinid
        ,COALESCE(b1.taxpaid,b2.taxpaid)    AS taxpaid
        ,COALESCE(b1.duedate,b2.duedate)    AS duedate
        ,COALESCE(b1.datepif,b2.datepif)    AS datepif
        ,COALESCE(b1.propdesc,b2.propdesc)  AS propdesc
    FROM rtadba.reasacct                  r
        INNER JOIN cwdba.txpyaccts        a ON r.accountno=t.accountno
        INNER JOIN cwdba.txpytaxid        t ON a.taxpayerno=t.taxpayerno
        LEFT OUTER JOIN trcdba.billspaid b1 ON t.custno=b1.custno AND b1.datepif > someconversionhere('01/06/2009') AND b1.datepif <= someconversionhere('01/06/2010')
        LEFT OUTER JOIN trcdba.billspaid b2 ON t.custno2=b2.custno AND b2.datepif > someconversionhere('01/06/2009') AND b2.datepif <= someconversionhere('01/06/2010')
    WHERE r.controlno = 1234567
      AND COALESCE(b1.custno,b2.custno) IS NOT NULL

создать индекс для каждого из них:

rtadba.reasacct.controlno and cover on accountno
cwdba.txpyaccts.accountno and cover on taxpayerno
cwdba.txpytaxid.taxpayerno and cover on custno
trcdba.billspaid.custno +datepif
trcdba.billspaid.custno2 +datepif
6 голосов
/ 31 марта 2010

Здесь то же самое, используя JOIN вместо подзапросов.

SELECT billyr, billno, propacct, vinid, taxpaid, duedate, datepif, propdesc
FROM billspaid
INNER JOIN txpytaxid
  ON txpytaxid.custno = billspaid.custno OR txpytaxid.custno = billspaid.custno2
INNER JOIN txpyaccts
  ON txpyaccts.taxpayerno = txpytaxid.taxpayerno
INNER JOIN reasacct
  ON reasacct.accountno = txpyaccts.accountno AND reasacct.controlno = 1234567
WHERE date(datepif) > '01/06/2009'
  AND date(datepif) <= '01/06/2010'

Однако, если OR в JOIN вызывает проблемы с производительностью, вы всегда можете попробовать использовать объединение:

(SELECT billyr, billno, propacct, vinid, taxpaid, duedate, datepif, propdesc
FROM billspaid
INNER JOIN txpytaxid
  ON txpytaxid.custno = billspaid.custno
INNER JOIN txpyaccts
  ON txpyaccts.taxpayerno = txpytaxid.taxpayerno
INNER JOIN reasacct
  ON reasacct.accountno = txpyaccts.accountno AND reasacct.controlno = 1234567
WHERE date(datepif) > '01/06/2009'
  AND date(datepif) <= '01/06/2010')
UNION
(SELECT billyr, billno, propacct, vinid, taxpaid, duedate, datepif, propdesc
FROM billspaid
INNER JOIN txpytaxid
  ON txpytaxid.custno = billspaid.custno2
INNER JOIN txpyaccts
  ON txpyaccts.taxpayerno = txpytaxid.taxpayerno
INNER JOIN reasacct
  ON reasacct.accountno = txpyaccts.accountno AND reasacct.controlno = 1234567
WHERE date(datepif) > '01/06/2009'
  AND date(datepif) <= '01/06/2010')
0 голосов
/ 31 марта 2010

Используйте EXISTS вместо IN (если только результирующий набор подзапроса IN не очень мал).

Если вы используете UNION вместо OR (что должно быть функционально эквивалентно), используйте вместо этого UNION ALL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...