Какие у вас есть ценности для RelatedUser
/UID
? Почему именно вы используете для этого NVARCHAR(100)
? NVARCHAR
обычно является ужасным выбором для поля PK/FK. Даже если значение представляет собой простой буквенно-цифровой код (например, ABTY1245
), есть более эффективные способы его обработки. Одна из основных проблем с NVARCHAR
(и даже с VARCHAR
для этой конкретной проблемы) заключается в том, что, если вы не используете двоичную сортировку (например, Latin1_General_100_BIN2
), каждая операция сортировки и сравнения будет применять весь спектр лингвистических правил, которые могут быть хорошо стоит при работе со строками, но при использовании кодов, но ненужно дорого, особенно при использовании типичных по умолчанию беззаботных коллайсов.
Некоторые «лучше» (но не идеально) решений будут:
- Если вам действительно нужны Unicode символов, по крайней мере указать двоичные сортировки, такие как
Latin1_General_100_BIN2
.
- Если вам не нужны символы Юникода, переключитесь на использование
VARCHAR
, который займет половину места и сортирует/сравнивает быстрее. Кроме того, по-прежнему используйте двоичную сортировку.
Лучше всего это:
- Добавить
INT IDENTITY
столбец в User
таблицы, названный UseID
- Сделать
UserID
кластеризированного PK
- Добавить столбец
INT
(не IDENTITY
) к Related
стол, названный UserID
- Добавить FK от
Related
Назад к User
по UserID
- Удалить столбец
RelatedUser
из таблицы Related
.
- Добавить некластеризованный, уникальный индекс к
User
таблице на UserCode
колонке (это делает его «альтернативный ключ»)
- падения и воссоздают
UserIdInput
пользовательского типа таблицы, чтобы иметь INT
тип данных вместо NVARCHAR(100)
- Если это вообще возможно, изменить
ID
столбец таблицы User
иметь двоичное объединение (т.е. Latin1_General_100_BIN2
)
- Если возможно, переименовать текущий
Id
столбец в таблице User
быть UserCode
или S что-то вроде этого.
- Если пользователи вводят значения «Код» (что означает: не может гарантировать, что они всегда будут использовать весь верхний регистр или все нижние регистры), то лучше всего добавить триггер
AFTER INSERT, UPDATE
в таблицу User
, чтобы убедиться, что значения всегда все в верхнем регистре (или все в нижнем регистре). Это также означает, что при поиске в «Кодексе» необходимо убедиться, что все входящие запросы используют одинаковые все верхние или все нижестоящие значения. Но эта небольшая часть дополнительной работы окупится.
Вся система поблагодарит вас и продемонстрирует вам свою признательность, будучи более эффективным :-).
Еще одна вещь, которую следует учитывать: TVP - это переменная таблицы, и по умолчанию они только когда-либо появляются оптимизатором запросов, чтобы иметь одну строку. Поэтому имеет смысл, что добавление нескольких тысяч записей в TVP замедлит его. Один трюк, который поможет ускорить TVP в этом сценарии, - это добавить OPTION (RECOMPILE)
в запрос. Повторная компиляция запросов с помощью переменных таблицы заставит оптимизатор запросов видеть истинный подсчет строк. Если это никому не помогает, другой трюк заключается в том, чтобы сбрасывать переменную таблицы TVP в локальную временную таблицу (то есть #TempUserIDs
), поскольку они поддерживают статистику и оптимизируют ее лучше, если в них содержится не более нескольких строк.
Из комментария OP по этому ответу:
[UID] является идентификатор, используемый по нашей системе (XXX-Y-ZZZZZZZZZZ ...), XXX, являющиеся буквами, Y означает число и Z являющиеся числами
Да, я полагал, что это идентификатор или код какого-то рода, так что это не меняет мой совет. NVARCHAR
, особенно если используется не двоичное, нечувствительное к регистру сопоставление, вероятно, является одним из наихудших вариантов типа данных для этого значения. Этот идентификатор должен находиться в столбце с именем UserCode
в таблице User
с некластеризованным индексом, определенным на нем. Это делает его «альтернативным» ключом и быстрый и простой поиск с уровня приложения, один раз, чтобы получить «внутреннее» целочисленное значение для этой строки, столбец INT IDENTITY
в качестве фактического UserID
(обычно лучше всего назвать столбцы имен как {table_name} ID для согласованности/упрощения обслуживания с течением времени). Значение UserID
INT - это то, что входит во все связанные таблицы как FK. Стол INT
ПРИСОЕДИНЯЙТЕСЬ много быстрее, чем NVARCHAR
. Даже используя двоичную сортировку, этот столбец NVARCHAR
, будучи быстрее его текущей реализации, по-прежнему будет составлять не менее 32 байт (на основе приведенного примера XXX-Y-ZZZZZZZZZZ
), тогда как INT
будет всего 4 байта. И да, эти дополнительные 28 байтов do имеют значение, особенно если у вас 13 миллионов строк. Помните, что это не просто пространство на диске, которое эти значения занимают, это также память, поскольку ВСЕ данные, которые считываются для запросов, проходят через буферный пул (то есть физическую память!).
В этом случае, однако, мы не следуем внешним ключам в любом месте, а напрямую запрашиваем их. Если они индексируются, это имеет значение?
Да, это по-прежнему имеет значение, поскольку вы выполняете ту же операцию, что и JOIN: вы берете каждое значение в основной таблице и сравниваете его со значениями в переменной таблицы/TVP. Это по-прежнему не двоичное, нечувствительное к регистру (я предполагаю) сравнение, которое очень медленное по сравнению с двоичным сравнением. Каждая буква должна оцениваться не только в верхнем и нижнем регистре, но и во всех других кодах Юникода, которые могут быть приравнены к каждой букве (и есть больше, чем вы думаете, что будет соответствовать A - Z
!). Индекс сделает его быстрее, чем не имеет индекса, но не так быстро, как сравнение простого простого значения, которое не имеет другого представления.
Рассматривали ли вы изменение своего ГДЕ СУЩЕСТВУЕТ СОЕДИНЕНИЕ. Объединяются, как правило, лучше, особенно с большими наборами. –
Насколько я могу использовать Google, EXISTS предпочтительнее, если вы проверяете существование, например, здесь предлагается ответ: http://stackoverflow.com/questions/7082449/exists-vs-join-and- use-of-exists- Не так ли? – bech
Да, но, как вы упомянули, производительность страдает по мере расширения вашего набора. Если ключ JOIN не индексируется, вы можете получить лучшие результаты с помощью EXISTS. Мое мышление это ... «Как куриный суп для холода ... не помешало бы попробовать». –