Подтвердить что ты не робот

SQL Server DELETE и SELECT ведут себя по-разному с тем же предложением WHERE

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

Недавно пользователи сообщили о нескольких дубликатах, которые восходят к началу октября 2011 года.... по величине сотен тысяч строк.

Я заметил странное поведение с удалением, которое выполняется для каждого задания:

DELETE FROM fm104d 
 WHERE location = '18'
   AND (CONVERT(datetime,CASE WHEN ISDATE(pull_date)=0 THEN '19000101' 
                 ELSE pull_date END)) >  DATEADD(day, -7, getdate())

Приведенное выше значение возвращает "(пострадали 0 строк)".

Когда я запускаю вышеуказанное после замены DELETE на SELECT *, я получаю 32 000 + строк взамен.

Почему SELECT и DELETE ведут себя по-другому?

UPDATE

Вот реальный план выполнения:

http://pastie.org/2869202

4b9b3361

Ответ 1

Ты не поверишь этому. Я не на самом деле, так как это почти не имеет логического смысла, но в конце концов, решение, которое сработало... должно было добавить индекс.

Кредит для этого относится к моему местному администратору баз данных "Думал ли о добавлении индекса? Я просто сделал это, чтобы проверить, и достаточно уверен, что он работает".

Здесь индекс добавлен:

CREATE  INDEX ixDBO_fir104d__SOURCE_LOCATION__Include
ON [dbo].[fir104d] ([SOURCE_LOCATION])
INCLUDE ([Transaction_Date],[PULL_DATE])
GO

Я запускаю задание как запланированное и, конечно же, все как есть.

Я предполагаю, что в плане объяснения есть что сказать, что он не использовал индекс/неправильный индекс, но мой ум разработчиков не может сильно понять этот уровень детализации.

Спасибо всем за потраченное время и усилия.

UPDATE

Полученные новости от другого разработчика о том, что данные в этой таблице дополнительно повреждены до того момента, когда потребовалось "несколько часов участия DBA для решения" вместе с разработчиком, который должен выполнить некоторые другие исправления данных (чтение: перезагрузка файлов данных),

В конце дня, добавив индекс, вероятно, было хорошо, учитывая, как работает запланированное задание, по-видимому, в истории было еще больше!

Ответ 2

Попробуйте следующее:

DELETE FROM fm104d  where fm104d.id in 
(
select  id from fm104d 
 WHERE location = '18'
   AND (CONVERT(datetime,CASE WHEN ISDATE(pull_date)=0 THEN '19000101' 
                 ELSE pull_date END)) >  DATEADD(day, -7, getdate())
)aaa

и дать ответ, если он удалит

p.s.: это не решение, но приведет к решению.

Ответ 3

Мне кажется, что вы никогда не захотите удалить, когда pull_date не является датой.
Попробуйте исключить явные замены строк... возможно, существует разбор между SELECT и DELETE

DELETE 
FROM 
    fm104d 
WHERE 
    [location] = '18' --NOTE if this is an int, then just try with 18, no dits
    AND (
         CASE ISDATE([pull_date])
         WHEN 1 THEN
             CAST([pull_date] AS DATETIME)
         ELSE
             NULL
         END  >  DATEADD(DAY, -7, GETDATE())
        ) 

РЕДАКТИРОВАТЬ: Обратите внимание, что это не соответствует вашему SQL, потому что в вашем случае, если вы вернетесь в январе, 1900, он удалит вашу строку независимо.... Я предположил, это не было вашим намерением.

Ответ 4

Одним из возможных объяснений может быть то, что есть две таблицы, каждая в другой схеме. Возможно, если у вас есть права select для обеих схем, но delete права только для одного, SQL Server может выбрать другую таблицу для delete.

Чтобы убедиться в этом, префикс вашей таблицы с именем схемы (схема по умолчанию dbo)

FROM schema1.fm104d

(Не тестировалось, просто мысль, нет доступа к установке SQL Server atm.)

Ответ 5

Для вашего выбора добавьте ISDATE(pull_date) в список выбора, чтобы определить, какая часть аргумента case влияет на них. Посмотрите также на pull_date и посмотрите, есть ли шаблон в формате строки, общей среди этих правонарушителей, которые отказываются быть удаленными.

Это может иметь некоторое отношение к детерминизму Convert и IsDate:

"ISDATE детерминирован только в том случае, если вы используете его с функцией CONVERT, если указан параметр стиля CONVERT, а стиль не равен 0, 100, 9 или 109."

См. пару примеров здесь, где convert вложен внутри isdate:

http://www.sqlmonster.com/Uwe/Forum.aspx/sql-server-programming/181/CAST-CONVERT-nondeterministic

Итак, попробуйте настроить предложение where и посмотреть, поможет ли это. Также обратите внимание, что "Возвращаемое значение ISDATE может зависеть от настроек LANGUAGE и DATEFORMAT". Так что, возможно, что-то на вашем сервере изменилось в этом отношении. Почему это повлияло на удаление, но не на выбор, все еще странно.

Ответ 6

Как пробовать это, посмотрите, можете ли вы сначала оценить столбец pull_date, а затем удалить записи.

DELETE FROM fm104d
WHERE Location = 18 
   AND Pull_date IN
   (
      SELECT CONVERT (DATETIME,
         CASE 
            WHEN ISDATE(pull_Date) = 0
               THEN '19000101'
            ELSE pull_date
         END) AS pull_date
      FROM fm104d 
      WHERE pull_date > DATEADD(DAY, -7, GETDATE())
   )