SQL-запрос для удаления самых старых строк с определенным количеством строк? - PullRequest
5 голосов
/ 01 апреля 2010

У меня есть таблица, которая содержит записи журнала для программы, которую я пишу. Я ищу идеи для SQL-запроса (я использую SQL Server Express 2005), который сохранит самое новое число записей X и удалит остальные. У меня есть столбец datetime, который является меткой времени для записи в журнале.

Я полагаю, что будет работать что-то вроде следующего, но я не уверен в производительности с предложением IN для большего количества записей. Производительность не критична, но я мог бы сделать все возможное в первый раз.

DELETE FROM MyTable WHERE PrimaryKey NOT IN
(SELECT TOP 10,000 PrimaryKey FROM MyTable ORDER BY TimeStamp DESC)

Я должен отметить, что этот запрос будет выполняться 3-4 раза в день (как часть другого процесса), поэтому количество записей, которые будут удалены с каждым запросом, будет небольшим по сравнению с количеством записей, которые будут сохраняется.

Ответы [ 5 ]

3 голосов
/ 01 апреля 2010

Попробуйте это:

DECLARE @X int
SELECT @X=COUNT(*) FROM MyTable 
SET @X=@X-10000

DELETE MyTable 
WHERE PrimaryKey IN (SELECT TOP(@x) PrimaryKey 
                     FROM MyTable 
                     ORDER BY TimeStamp ASC
                    ) 

вид зависит от того, удаляется ли менее 10000 строк, если это так, это может выполняться быстрее, так как оно определяет строки, которые нужно удалить, а не строки, которые нужно сохранить.

2 голосов
/ 01 апреля 2010

Попробуйте, используйте CTE для получения порядкового номера строки, а затем удаляете только X строк одновременно. Вы можете изменить эту переменную в соответствии с вашим сервером.

Добавление подсказки таблицы ReadPast должно предотвратить блокировку.

DECLARE @numberToDelete INT;
DECLARE @ROWSTOKEEP INT;
SET @ROWSTOKEEP = 50000;
SET @numberToDelete =1000;

WHILE 1=1
BEGIN
    WITH ROWSTODELETE AS
    (
        SELECT ROW_NUMBER() OVER(ORDER BY dtsTimeStamp DESC) rn,
            *
        FROM MyTable 

    )
    DELETE TOP (@numberToDelete) FROM ROWSTODELETE WITH(READPAST)
    WHERE rn>@ROWSTOKEEP;

    IF @@ROWCOUNT=0
        BREAK;
END;
1 голос
/ 01 апреля 2010

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

  1. Создать новую копию таблицы журнала с новым именем
  2. Вставьте в новую таблицу последние 10000 записей из исходной таблицы.
  3. Удалить исходную таблицу (или переименовать)
  4. Переименуйте новую таблицу в правильное имя

Это, очевидно, требует больше размышлений, чем просто удаление строк (например, если в таблице есть столбец IDENTITY, это необходимо установить в новой таблице и т. Д.). Но если у вас большая таблица, было бы более эффективно скопировать 10 000 строк в новую таблицу, а затем удалить исходную таблицу, чем пытаться удалить миллионы строк, чтобы оставить только 10 000.

1 голос
/ 01 апреля 2010
DELETE FROM MyTable 
WHERE TimeStamp < (SELECT min(TimeStamp) 
                   FROM (SELECT TOP 10,000 TimeStamp 
                         FROM MyTable 
                         ORDER BY TimeStamp DESC))

или

DELETE FROM MyTable 
WHERE TimeStamp < (SELECT min(TimeStamp) 
                   FROM MyTable 
                   WHERE PrimaryKey IN (SELECT TOP 10,000 TimeStamp 
                                        FROM MyTable 
                                        ORDER BY TimeStamp DESC))

Не уверен, что это улучшение с точки зрения эффективности.

1 голос
/ 01 апреля 2010

Ваш запрос примерно так же эффективен, как и может быть прочитан.

NOT IN и NOT EXISTS более эффективны, чем LEFT JOIN/IS NULL, но только потому, что оба столбца никогда не могут быть нулевыми. Вы можете прочитать эту ссылку для более глубокого сравнения .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...