Получить случайную строку из таблицы — попытаться оптимизировать запрос — SQL Server

#.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. Как выглядит ваш план выполнения? Это должен быть ваш первый порт захода, поскольку он укажет, где он проводит время. Кроме того, каково ваше целевое время запроса?