2016-02-04 3 views
1

Я получаю другой ответ между двумя утверждениями, которые я бы счел эквивалентными: SELECT COUNT(*) - NOT EXISTS. В ~ 49 из 50 казней эти два утверждения ведут себя одинаково, но иногда они этого не делают.Разница между NOT EXISTS и COUNT (*)

Я предполагаю, что существует различие между тем, как эти заявления обрабатывают заблокированные страницы или что-то, может быть, что-то более «далеко». Мой вопрос в чем разница?

Я изначально добавил некоторые записи (ЗАЯВЛЕНИЕ 3) на мой SPROC, который, как я видел, имел разные значения. Поскольку содержимое TableWithResults может измениться в то время как это SPROC выполняется, это я добавил ЗАЯВЛЕНИЕ № 3, чтобы я мог подтвердить результат COUNT(*) до и после NOT EXISTS:

-- STATEMENT 1: If this is returning 1... 
SET @MatchingResultCount1 = (SELECT COUNT (*) FROM TableWithResults WHERE SearchId = @SearchId) 

-- STATEMENT 2: ...I expect this to evaluate "False" and sets IS_VALID='Y' 
IF NOT EXISTS (SELECT * FROM TableWithResults WHERE SearchId = @SearchId) 
    SET @IS_VALID = 'N'; 
ELSE 
    SET @IS_VALID = 'Y'; 

-- STATEMENT 3: This is to confirm the table didn't change 
SET @MatchingResultCount1 = (SELECT COUNT (*) FROM TableWithResults WHERE SearchId = @SearchId) 

Что я вижу это @MatchingResultCount1@MatchingResultCount2 и являются 100% всегда одинаковы. Почти все время @IS_VALID = 'Y' когда @MatchingResultCount1 > 0, но 1/50 раз, @IS_VALID = 'N' когда @MatchingResultCount1 > 0.

Я пробовал использовать WITH (NOLOCK) для всех заявлений, и это, похоже, не помогло.

+0

Где не существует? один в условии if? если да, то как этот вопрос в count (*) vs не существует? –

+0

У вас есть указатель на SearchId? возможно, при использовании count, SQL-сервер использует данные в таблице, но при использовании существует индекс, и ваш индекс может быть поврежден. Это может быть вздор, но это просто мысль. – FLICKER

+0

Я не вижу вашей объясненной логики или '@ MatchingResultCount2', реализованной в вашем скрипте, и кажется, что ваш тест неповторим. Может быть, ваш соответствующий ряд будет удален между –

ответ

2

Вы должны, как правило, предпочитают NOT EXISTS над COUNT(*) по очень простой причине:

Когда вы говорите COUNT(*), база данных не знает, что вы на самом деле не заботиться о количестве строк точным. Таким образом, он не может пропустить оставшиеся результаты, как только не менее найдена одна строка, соответствующая предложению WHERE.

Теперь, как побочный эффект, это также может привести к COUNT(*) запрос приобретает больше блокировок, чем NOT EXISTS запрос в случае NOT EXISTS удается пропустить строки. Это будет зависеть от базы данных (я не уверен в SQL Server)

0

Здесь вы можете немного упростить свою логику.

DECLARE @IS_VALID char(1) = 'N' 

IF EXISTS (SELECT * FROM TableWithResults WHERE SearchId = @SearchId) 
    SET @IS_VALID = 'Y'; 

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