Чрезвычайно медленный запрос при попытке COUNT (id) для каждой строки в результатах - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть таблица с журналами разговоров. Каждое сообщение представляет собой строку таблицы, и каждый диалог состоит из нескольких строк, которые имеют одинаковые значения conversationId.

Я выбираю уникальные conversationId s за последний месяц вместе с другими столбцами (такими как текст и метка времени) из самого последнего сообщения в каждом диалоге.

Это прекрасно работает, и запрос занимает около 1 секунды или меньше:

SELECT 
    *

FROM
    (
      SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY conversationId ORDER BY id DESC) AS rn

        FROM Logs 

        WHERE 
            timestamp >= DATEADD(month, -1, GETDATE())
    ) AS t

WHERE 
    t.rn = 1

ORDER BY
    timestamp DESC

Теперь я также хочу добавить новый столбец messageCount, в котором содержится количество всех сообщений за любое время для каждого conversationId.

Для этого я добавил еще одну строку в запрос:

SELECT 
    *, 
    (SELECT COUNT(id) FROM Logs WHERE conversationId = t.conversationId) AS messageCount

FROM
    (
      SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY conversationId ORDER BY id DESC) AS rn

        FROM Logs 

        WHERE 
            timestamp >= DATEADD(month, -1, GETDATE())
    ) AS t

WHERE 
    t.rn = 1

ORDER BY
    timestamp DESC

Возвращает правильные результаты, но в пять раз медленнее, чем 5 секунд, когда в результирующей таблице всего 14 строк.

Что я здесь не так делаю и как мне сделать этот запрос быстрее?

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Вы можете попробовать вызвать COUNT как аналитическую функцию непосредственно в подзапросе:

WITH cte AS (
    SELECT *,
       ROW_NUMBER() OVER (PARTITION BY conversationId ORDER BY id DESC) AS rn,
       COUNT(id) OVER (PARTITION BY conversationId) messageCount
    FROM Logs 
    WHERE 
        timestamp >= DATEADD(month, -1, GETDATE())
)

SELECT *
FROM cte
WHERE rn = 1;

По крайней мере, это позволяет избежать потенциально дорогостоящих коррелированных подзапросов, которые вы использовали. Кроме того, если вышеупомянутое все еще слишком медленное для вас, то следующим шагом будет рассмотрение плана выполнения.

0 голосов
/ 18 сентября 2018

Row_number медленнее, если в столбце id есть индекс, поэтому вы можете использовать подзапрос, как показано ниже:

select t.conversationId, count(id) as messagecount 
from logs t 
where t.id in (
    SELECT MAX(t1.id)
    from logs t1
    WHERE t1.conversationId = t.conversationId
    GROUP BY t1.conversationId
) and timestamp >= DATEADD(month, -1, GETDATE()) 
group by t.conversationId
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...