#sql-server-2008 #tsql
#sql-server-2008 #tsql
Вопрос:
У меня есть запрос, который должен получить первый и второй по величине артикул в списке пожеланий каждого участника. Приведенный ниже запрос работает, но это занимает слишком много времени, потому что существует около 9 миллионов пользователей, и у каждого пользователя есть около 10 элементов списка желаний, поэтому вы можете видеть, что приведенный ниже запрос никогда не завершится.
SELECT MAX(CASE WHEN wl.rank = 1 THEN wl.SKU ELSE NULL END) AS [highestSku],
MAX(CASE WHEN wl.rank = 2 THEN wl.SKU ELSE NULL END) AS [secondHighestSku],
FROM Member m
LEFT JOIN (SELECT *
FROM (SELECT DENSE_RANK() OVER (PARTITION BY wl.MemberID ORDER BY wli.Price DESC) AS rank, wl.MemberID, wli.SKU
FROM WishListItem wli
INNER JOIN WishList wl ON wli.WishListID = wl.ID) T1) w ON w.MemberID = m.ID
Мой вопрос в том, есть ли лучший способ получить верхние первую и вторую записи для каждого пользователя? Если нет, есть ли способ оптимизировать этот запрос? В идеале, если я смогу восстановить количество уровней, извлеченных из запроса ранжирования (тот, у которого есть DENSE_RANK ()), это мне поможет. Я хотел сделать что-то вроде WHERE DENDS_RANK() <= 2, но это невозможно, и выполнение этого вне скобок противоречит цели soultion.
Кроме того, это всего лишь часть запроса. На самом деле у меня есть еще больше левых соединений в большем количестве таблиц, в которых столько же элементов, и мне нужно получить верхние 1 и 2 записи для каждого пользователя.
И это должно быть сделано в одном запросе или как можно больше в одном, потому что я добавляю его в таблицу данных. Я также могу уменьшить количество записей, т.Е.. ВЕРХНИЕ 1000 и разбейте запрос, но мне нужно будет иметь возможность продолжить с того места, где я остановился … кроме того, я попробовал TOP 1000, и через 10 минут я отменил запрос, потому что мне нужно извлечь все 9 миллионов записей.
Комментарии:
1. есть ли у вас индексы в какой-либо из таблиц?
2. да, таблицы полностью проиндексированы. Я заметил, что я даже не могу выполнить прямой SELECT * FROM member без того, чтобы SQL не исчерпал память, потому что записей слишком много.
3. для начала попробуйте обновить статистику индекса
4. Я не уверен, что понимаю ваш дизайн, почему цена указана в таблице списка пожеланий, а артикул — в WLI? Я бы ожидал, что Member <- WishList <- WishlistItem -> Product или что-то в этом роде. Вы уверены, что это правильно?
5. исправлено. Я переписал код, чтобы извлечь его из большого запроса.
Ответ №1:
Я бы взял относительно небольшое подмножество данных, поместил его в табличную переменную и запустил запрос к ней вместо основных (и, вероятно, очень «загруженных») таблиц:
DECLARE @Member TABLE
(
ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
-- add necessary columns to this definition.
)
INSERT INTO @Member (field1, field2...)
SELECT field1, field2 -- etc.
FROM YourTables
WHERE SomeCriteria = Whatever
Убедитесь, что предложение WHERE определяет более узкое подмножество данных, чем ваши рабочие таблицы. Если производительность все еще страдает, вы могли бы создать табличные переменные для других объединяемых таблиц, а затем использовать их в окончательном запросе.