Расхождение в количестве записей в SQL Server - PullRequest
0 голосов
/ 30 ноября 2018

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

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

  • Я смотрю на данную таблицу (назовите ее TABLE_X) и
  • некоторые конкретные предикаты (скажем,A, B, C и D), которые я ожидаю сделать взаимоисключающими, но не охватывающими всю таблицу ...
  • Я ожидаю запрос на пересечение любой пары предикатов (например, WHERE (A)И (B)) не возвращать никаких записей, и это подтверждается случаем
  • Если в таблице 5 000 500 записей, а объединение предикатов имеет 2 000 000 записей, я ожидаю, что в дополнении объединения будет 3 000 500 записей;этот последний момент - то, где я достиг проблемы

В теме подсчета записей, вот что я нашел:

  • , если я выберу count (1)из TABLE_X я получаю (например) 5 000 500 записей
  • , если выбрать число (1) из TABLE_X, где (A) или (B) или (C) или (D) я получу 2 000 000 записей
  • если я выбираю count (1) из TABLE_X, где нет ((A) или (B) или (C) или (D)), я получаю 3 000 000 записей
  • , если я выбираю count (1) изTABLE_X, где нет ((A) или (B) или (C) или (D)) или ((A) или (B) или (C) или (D)), я получаю 5 000 000 записей

Итак, я вижу объединение предиката и его дополнения, приводящее к меньшему количеству элементов, чем количество элементов самой таблицы.Кажется, это не поддается логике.

Естественно, я спрашивал себя, оказывают ли значения NULL какой-то эффект.Обратите внимание, что предикаты A, B, C и D являются довольно простыми логическими выражениями, включающими все столбцы, например: c1, c2 и c3.То, что я нашел, не прояснило для меня вопроса:

  • , если я выберу count (1) из TABLE_X, где нет ((A) или (B), (C) или (D)) и ((c1 равен нулю) или (c2 равен нулю) или (c3 равен нулю)), я получаю 550 записей
  • , если я выберу count (1) из TABLE_X, где ((A) или (B) или (C)или (D)) и ((c1 равно нулю) или (c2 равно нулю) или (c3 равно нулю)), я получаю 0 записей

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

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

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

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

Поэтому мой вопрос: как я могу определить, почему я вижу количество записей, которые кажутся не поддающимися логике (как отмечено выше)?

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

1 Ответ

0 голосов
/ 30 ноября 2018

Переписывание моего комментария в качестве ответа на запрос OP.

Это может произойти по нескольким причинам:

  • у вас может быть логическая ошибка в ваших предикатах
  • Может быть некоторая настройка на уровне сеанса, которая слегка изменяет способ оценки предикатов (вкл. / Выкл. Нуля или подобное)
  • Может быть ошибка в SQL Server (встречается не очень часто, но еслитогда команда SQL захочет помочь разобраться и исправить это)

Вы заявили в своем посте, что пытались выполнять вызовы на основе CTE, чтобы посмотреть на различные шаблоны, которые вы пытались сузитьвниз ошибка.Основываясь на том, как SQL Server анализирует и компилирует эти запросы, вы должны попробовать другой подход.CTE рассматриваются как представления и выстраиваются во время компиляции.Итак, если в SQL есть логическая ошибка (третий случай), то добавление CTE просто повторит ту же проблему в ваших экспериментах и ​​не обязательно поможет вам сузить круг.

Я предлагаю вам принять результатыкаждый из ваших индивидуальных тестов и поместите их в временные таблицы.Затем я предлагаю вам запустить эти временные таблицы с запросами EXCEPT ALL / INTERSECT ALL для исходного запроса и других шаблонов, чтобы сузить 500 строк, для которых вы не можете учесть.Если вы можете найти эти конкретные строки, вы, скорее всего, сделаете меньшее воспроизведение, которое изолирует проблему.(Если вам нужно было обратиться в службу поддержки клиентов Microsoft, это поможет ускорить этот процесс, получив минимальное повторение вашей проблемы, выявленной до их вызова).

Надеюсь, это поможет разобраться в вашей загадке.Желаем удачи.

Conor

Архитектор, SQL Server

...