#.net #sql #sql-server
#.net #sql #sql-сервер
Вопрос:
Мне нужно взять случайную строку из таблицы. Сначала я написал SP следующим образом:
SELECT * FROM
(SELECT TOP 1
*
FROM PeopleTales PT
LEFT JOIN PeopleTalesCategories PTC ON PT.CategoryAn = PTC.Analit
WHERE LEN(PT.Text) > 900
ORDER BY NEWID()
) t1
Это не очень хорошо по статистике времени:
Среднее общее время выполнения = 200.
Затем я попытался взять строку вручную:
WITH CTE_t
AS
(
SELECT
ROW_NUMBER () OVER (ORDER BY PT.Analit) AS RowNumber,
*
FROM PeopleTales PT
LEFT JOIN PeopleTalesCategories PTC ON PT.CategoryAn = PTC.Analit
WHERE LEN(PT.Text) > 900
)
SELECT * FROM CTE_t
WHERE CTE_t.RowNumber = 1 ABS(CHECKSUM(NewId())) % (SELECT COUNT(CTE_t.RowNumber) FROM CTE_t)
Это немного лучше по времени выполнения, но иногда у меня было 0 строк, иногда 1,2 или даже 3 строки в результате! я знаю, что использование CTE не очень хорошо. Это не решение.
Среднее общее время выполнения = 60.
Итак, следующий шаг:
SELECT * FROM (
SELECT
ROW_NUMBER () OVER (ORDER BY PT.Analit) AS RowNumber,
*
FROM PeopleTales PT
LEFT JOIN PeopleTalesCategories PTC ON PT.CategoryAn = PTC.Analit
WHERE LEN(PT.Text) > 900
) t1
WHERE t1.RowNumber = (SELECT 1 ABS(CHECKSUM(NewId())) % (SELECT
COUNT(Analit)
FROM PeopleTales
WHERE LEN(Text) > 900))
Каждый раз, когда у меня есть только одна строка, и все в порядке с общим временем выполнения.
Среднее общее время выполнения = 60.
Итак, есть ли еще способы взять случайную строку или оптимизировать мой запрос?
Большое спасибо за ответы.
Ответ №1:
Сколько строк в таблице и можно ли изменить вашу схему? Одна из проблем заключается в том, что все выборки основаны на LEN (столбец), поэтому SQL Server не может эффективно использовать индекс.
Возможно, вам захочется рассмотреть вычисляемый столбец и поместить в него индекс. Что-то вроде:
ALTER TABLE PeopleTales ADD TextLength AS LEN(PT.Text)
GO
CREATE INDEX IX_PeopleTales_TextLen ON PeopleTales (Text, CategoryAN)
GO
Я включаю CategoryAN
, чтобы соединение выполнялось исключительно по индексу (и означает, что SQL Server не должен выполнять поиск по закладке или ключу).
Затем, очевидно, измените свои запросы так, чтобы это WHERE LEN(PT.Text) > 900
стало WHERE TextLength > 900
.
Комментарии:
1. 1. Существует 2000 строк, и да — я могу изменить схему. 2. Да, это помогает снизить среднее время выполнения до 45-50. Но, если что-то не так / неправильно в запросе, что можно переписать?
2. Как выглядит ваш план выполнения? Это должен быть ваш первый порт захода, поскольку он укажет, где он проводит время. Кроме того, каково ваше целевое время запроса?