Время выполнения SQL-запроса быстрое, но выборка строк медленная - PullRequest
0 голосов
/ 09 апреля 2011

Это вопрос из двух частей, но сначала некоторая справочная информация:

У меня есть запрос TSQL в Sybase, который сообщает, что время выполнения составляет 0,328 секунды, однако для получения приблизительно 5000 строк требуется около 20-30 секунд. Запрос имеет два подзапроса и левое внешнее объединение.

Запрос выглядит примерно так:

SELECT CustomerContact.Id, Customer.Name, ... 
     , CustomerContacts.LastName, CustomerContacts.FirstName
     , ( SELECT max(LastModified)
             FROM ContactPhone
             WHERE ContactPhone.ContactID = CustomerContact.ID
       ) as PhoneLastModified
     , ( SELECT max(LastModified)
             FROM ContactEmail
             WHERE ContactEmail.ContactID = CustomerContact.ID
       ) as EmailLastModified
    FROM CustomerContacts
    LEFT OUTER JOIN Customer
        ON Customer.ID = CustomerContact.CustomerId
    WHERE (PhoneLastModified > '2011-01-01'
        OR EmailLastModified > '2011-01-01')

Что я делаю, так это выбираю записи клиентов на основе даты последнего изменения любой связанной контактной информации. ContactPhone и ContactEmail могут содержать x количество записей для любой данной строки в CustomerContact. Таблица Customer является однозначной с CustomerContact.

Теперь мой вопрос:

  1. Почему Sybase сообщает, что время выполнения составляет 0,328 секунды, но на самом деле для извлечения строк в запросе требуется более 30 секунд?

  2. Что я могу сделать, чтобы оптимизировать этот запрос?

Моя первая мысль - добавить индексы в столбцы LastModified, но я имею дело с небольшим количеством записей.

Моя вторая мысль заключается в том, что подзапросы замедляют работу, и что я должен преобразовать их в объединения. Но я не могу использовать агрегатную функцию max в условии Join, так как я могу получить только строку max в моем объединении?

Спасибо

Ответы [ 3 ]

2 голосов
/ 09 апреля 2011

Я предполагаю, что 2 коррелированных подзапроса в предложении select не выполняются, пока не будут возвращены строки. В общем, следует избегать коррелированных подзапросов, так как они имеют тенденцию быть медленными, конечно, всегда есть исключения!

Попробуйте переместить ContactPhone и Contact Email в объединенный подзапрос.

SELECT 
    cc.Id, 
    c.Name,
    ... , 
    cc.LastName, CustomerContacts.FirstName,
    cp.LastModified PhoneLastModified
    ce.LastModified EmailLastModified
FROM 
    CustomerContacts cc
LEFT OUTER JOIN 
    Customer c 
ON 
    c.ID = cc.CustomerId
INNER JOIN 
    (SELECT
        ContactId,
        max(LastModified) as LastModified
     FROM
        ContactPhone
     WHERE
         LastModified > '2011-01-01'
     GROUP BY
     ContactId ) cp
ON 
    cp.ContactID = cc.ID
INNER JOIN 
    (SELECT
        ContactId,
        max(LastModified) as LastModified
     FROM
        ContactEmail
     WHERE
         LastModified> '2011-01-01'
     GROUP BY
     ContactId ) ce
ON 
    ce.ContactID = cc.ID
1 голос
/ 09 апреля 2011

Теперь я вижу, что он использует SYBASE, а не SQL Server (может быть и TSQL), но я оставлю ответ другим, кто использует продукт MS.

Вот версия CTE.Работает так же, как версия Пола, но немного легче для чтения:

WITH MaxContactPhone AS
(
   SELECT max(LastModified) as LastModified, ContactID 
   FROM ContactPhone
   WHERE LastModified> '2011-01-01'
   GROUP BY ContactID
), MaxContactEmail AS
(
   SELECT max(LastModified) as LastModifed, ContactID
   FROM ContactEmail
   WHERE LastModified> '2011-01-01'
   GROUP BY ContactID
)
SELECT CustomerContact.Id, Customer.Name, ... , CustomerContacts.LastName, 
       CustomerContacts.FirstName,
       MaxContactPhone.LastModified as PhoneLastModified,
       MaxContactEmail.LastModified as EmailLastModified
    FROM CustomerContacts
    LEFT OUTER JOIN Customer ON Customer.ID = CustomerContact.CustomerId
    JOIN MaxContactPhone ON CustomerContact.CustomerId = MaxContactPhone.ContactID AND 
    JOIN MaxContactEmail ON CustomerContact.CustomerId = MaxContactEmail.ContactID
0 голосов
/ 10 апреля 2011
SELECT cc.ID, cu.Name, ... 
     , cc.LastName, cc.FirstName
     , g.PhoneLastModified
     , g.EmailLastModified
    FROM CustomerContacts cc
    LEFT JOIN Customer cu
        ON cu.ID = cc.CustomerID
    JOIN 
      ( SELECT cc.ID
             , max(cp.LastModified)
               AS PhoneLastModified
             , max(ce.LastModified)
               AS EmailLastModified
            FROM CustomerContacts cc
            LEFT JOIN ContactPhone cp
                ON cp.ContactID = cc.ID
            LEFT JOIN ContactEmail ce
                ON ce.ContactID = cc.ID
            GROUP BY cc.ID
            HAVING ( PhoneLastModified > '2011-01-01'
                  OR EmailLastModified > '2011-01-01' )
      ) AS g
        ON g.Id = cc.id
...