COUNT (DISTINCT column_name) Расхождение с COUNT (column_name) в SQL Server 2008? - PullRequest
12 голосов
/ 30 сентября 2011

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

 SELECT COUNT(distinct  Member_List_Link.UserID)  
 FROM Member_List_Link  with (nolock)   
 INNER JOIN MasterMembers with (nolock)  
     ON Member_List_Link.UserID = MasterMembers.UserID   
  WHERE MasterMembers.Active = 1 And
        Member_List_Link.GroupID = 5 AND 
        MasterMembers.ValidUsers = 1 AND 
        Member_List_Link.Status = 1

Но если я выполню тот же запрос без отличного ключевого слова, я получу счет 233,748

 SELECT COUNT(Member_List_Link.UserID)  
 FROM Member_List_Link  with (nolock)   
 INNER JOIN MasterMembers with (nolock)
   ON Member_List_Link.UserID = MasterMembers.UserID   
 WHERE MasterMembers.Active = 1 And Member_List_Link.GroupID = 5 
  AND MasterMembers.ValidUsers = 1 AND Member_List_Link.Status = 1

Чтобы проверить, я заново создал все таблицы и поместил их во временные таблицы и снова выполнил запросы:

  SELECT COUNT(distinct  #Temp_Member_List_Link.UserID)  
  FROM #Temp_Member_List_Link  with (nolock)   
  INNER JOIN #Temp_MasterMembers with (nolock)
    ON #Temp_Member_List_Link.UserID = #Temp_MasterMembers.UserID   
  WHERE #Temp_MasterMembers.Active = 1 And 
        #Temp_Member_List_Link.GroupID = 5 AND 
        #Temp_MasterMembers.ValidUsers = 1 AND 
        #Temp_Member_List_Link.Status = 1

И без отдельного ключевого слова

  SELECT COUNT(#Temp_Member_List_Link.UserID)  
  FROM #Temp_Member_List_Link  with (nolock)   
  INNER JOIN #Temp_MasterMembers with (nolock)
    ON #Temp_Member_List_Link.UserID = #Temp_MasterMembers.UserID   
  WHERE #Temp_MasterMembers.Active = 1 And 
        #Temp_Member_List_Link.GroupID = 5 AND 
        #Temp_MasterMembers.ValidUsers = 1 AND 
        #Temp_Member_List_Link.Status = 1

На заметке сторон, я воссоздал временные таблицы, просто выполнив (select * from Member_List_Link into #temp...)

И теперь, когда я проверяю, чтобы увидеть разницу между COUNT (столбец) и COUNT(отдельный столбец) с этими временными таблицами я не вижу ни одной!

Так почему же существует несоответствие с исходными таблицами?

Я использую SQL Server 2008 (Dev Edition).

ОБНОВЛЕНИЕ - Включая профиль статистики

Столбец PhysicalOp только для первого запроса (без отдельного)

NULL
Compute Scalar
Stream Aggregate
Clustered Index Seek

Столбец PhysicalOp только для первого запроса (с отличным)

NULL
Compute Scalar
Stream Aggregate
Parallelism
Stream Aggregate
Hash Match
Hash Match
Bitmap
Parallelism
Index Seek
Parallelism
Clustered Index Scan

Строки и Выполнения для 1-го запроса (без отличительных)

1   1
0   0
1   1
1   1

Строки и Выполнения для 2-го запроса (с различными)

Rows    Executes
1   1
0   0
1   1
16  1
16  16
233767  16
233767  16
281901  16
281901  16
281901  16
234787  16
234787  16

Добавление OPTION (MAXDOP 1) во 2-й запрос (с различными)

Rows Executes

1           1
0           0
1           1
233767          1
233767          1
281901          1
548396          1

Ирезультирующий PhysicalOp

NULL
Compute Scalar
Stream Aggregate
Hash Match
Hash Match
Index Seek
Clustered Index Scan

Ответы [ 6 ]

4 голосов
/ 09 октября 2011

ОТ http://msdn.microsoft.com/en-us/library/ms187373.aspx NOLOCK Эквивалент READUNCOMMITTED.Дополнительные сведения см. В разделе «READUNCOMMITTED» далее в этом разделе.

«READUNCOMMITED» будет считывать строки дважды, если они являются объектом перехода, поскольку в базе данных существуют транзакции как отката, так и отката, когда транзакция выполняется.

По умолчанию все запросы считываются подтвержденными, что исключает незафиксированные строки

Когда вы вставляете во временную таблицу, выборка даст вам только подтвержденные строки - я полагаю, что это охватывает все симптомы, которые вы пытаетесьобъяснить

1 голос
/ 09 октября 2011

Трудно воспроизвести это поведение, поэтому я бью в темноте:

Оператор WITH (NOLOCK) позволяет читать незафиксированные данные. Я предполагаю, что вы добавили это, чтобы ничего не блокировать для ваших пользователей? Если вы удалите их и выдадите

SET TRANSACTION ISOLATION LEVEL READ COMMITTED

Перед выполнением запроса вы должны получить более надежные результаты. Но тогда таблицы могут получать блокировки при выполнении запроса.

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

1 голос
/ 08 октября 2011

Я думаю, что получил ответ на ваш вопрос, но сначала скажите, является ли userid первичным ключом в вашей исходной таблице?

, если да, то запрос CTAS для создания временной таблицы не будет копировать первичный ключисходная таблица, она только копирует ограничение NOT NULL, которое не является частью первичного ключа..fine?

. Теперь, что случилось, у вашей исходной таблицы был первичный ключ, поэтому в count (имя_столбленного столбца) не входят кортежи с нулевыми записями ив то время как вы создали временные таблицы, первичный ключ не копируется и, следовательно, ограничение NOT NULL не попадает во временную таблицу !!

Вам это ясно?

0 голосов
/ 03 октября 2011

при использовании счетчика с отдельным столбцом он не учитывает столбцы со значениями null.

создать таблицу #tmp (name char (4) null)

вставить в значения #tmp (null)

вставить в значения #tmp (null)

вставить в значения #tmp ("AAA")

Запрос: - 1> выберите количество (*) из #tmp 2> go


       3

1> выберите количество (отличное имя) из #tmp 2> go


       1

1> выбрать другое имя из #tmp 2> идти Имя


NULL

AAA

но работает в производной таблице

1> выберите количество (*) из (выберите другое имя из #tmp) a

2> go


       2

Примечание: - Я тестировал его в Sybase

0 голосов
/ 30 сентября 2011

Рэй, пожалуйста, попробуйте следующее

SELECT COUNT(*)
FROM 
(
    SELECT Member_List_Link.UserID, ROW_NUMBER() OVER (PARTITION BY Member_List_Link.UserID ORDER BY (SELECT NULL)) N
    FROM Member_List_Link  with (nolock)   
    INNER JOIN MasterMembers with (nolock)  
        ON Member_List_Link.UserID = MasterMembers.UserID   
     WHERE MasterMembers.Active = 1 And
           Member_List_Link.GroupID = 5 AND 
           MasterMembers.ValidUsers = 1 AND 
           Member_List_Link.Status = 1
) A
WHERE N = 1
0 голосов
/ 30 сентября 2011

Какой результат вы получите с

SELECT count(*) FROM (
    SELECT distinct  Member_List_Link.UserID
    FROM Member_List_Link  with (nolock)
    INNER JOIN MasterMembers with (nolock)
      ON Member_List_Link.UserID = MasterMembers.UserID
    WHERE MasterMembers.Active = 1 And
         Member_List_Link.GroupID = 5 AND 
         MasterMembers.ValidUsers = 1 AND
         Member_List_Link.Status = 1
) as m

И С:

SELECT count(*) FROM (
    SELECT distinct  Member_List_Link.UserID
    FROM Member_List_Link  
    INNER JOIN MasterMembers
      ON Member_List_Link.UserID = MasterMembers.UserID
    WHERE MasterMembers.Active = 1 And
         Member_List_Link.GroupID = 5 AND 
         MasterMembers.ValidUsers = 1 AND
         Member_List_Link.Status = 1
) as m
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...