Создание индекса для табличной переменной
можете ли вы создать index
для переменной таблицы в SQL Server 2000
?
то есть
DECLARE @TEMPTABLE TABLE (
[ID] [int] NOT NULL PRIMARY KEY
,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL
)
могу ли я создать индекс по имени?
2 ответов
вопрос помечен SQL Server 2000, но в интересах людей, разрабатывающих последнюю версию, я сначала рассмотрю это.
SQL Server 2014
в дополнение к методам добавления индексов на основе ограничений, описанных ниже, SQL Server 2014 также позволяет указывать не уникальные индексы непосредственно со встроенным синтаксисом в объявлениях переменных таблицы.
пример синтаксиса для этого под.
/*SQL Server 2014+ compatible inline index syntax*/
DECLARE @T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/
C2 INT INDEX IX2 NONCLUSTERED,
INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/
);
фильтрованные индексы и индексы с включенными столбцами в настоящее время не могут быть объявлены с этим синтаксисом, однако SQL Server 2016 расслабляет это немного дальше. Из CTP 3.1 теперь можно объявлять отфильтрованные индексы для табличных переменных. По RTM это мая в случае, если включенные столбцы также разрешены, но текущая позиция заключается в том, что они " скорее всего не попадет в SQL16 из-за ресурса ограничения"
/*SQL Server 2016 allows filtered indexes*/
DECLARE @T TABLE
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/
)
SQL Server 2000-2012
могу ли я создать индекс по имени?
короткий ответ: да.
DECLARE @TEMPTABLE TABLE (
[ID] [INT] NOT NULL PRIMARY KEY,
[Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL,
UNIQUE NONCLUSTERED ([Name], [ID])
)
более подробный ответ ниже.
традиционные таблицы в SQL Server могут иметь кластеризованный индекс или структурированы как кучи.
кластеризованные индексы могут быть объявлены как уникальные запретить дублировать Ключевые значения или значение по умолчанию non unique. Если не уникальный, то SQL Server молча добавляет uniqueifier для любых дубликатов ключей, чтобы сделать их уникальными.
некластеризованные индексы также могут быть явно объявлены уникальными. В противном случае для не уникального случая SQL Server добавляет указатель на строку (ключ кластеризованного индекса или RID для кучи) для всех ключей индекса (а не только дубликатов) это снова гарантирует, что они уникальны.
в SQL Server 2000 - 2012 индексы переменных таблицы могут быть созданы неявно только путем создания UNIQUE
или PRIMARY KEY
ограничения. Разница между этими типами ограничений заключается в том, что первичный ключ должен находиться в столбце(столбцах), не имеющих значения null. Столбцы, участвующие в уникальном ограничении, могут быть nullable. (хотя реализация SQL Server уникальных ограничений при наличии NULL
s не соответствует указанному в стандарте SQL). Также таблица может иметь только один первичный ключ, но несколько уникальных ограничения.
оба этих логических ограничения физически реализованы с уникальным индексом. Если явно не указано иное, то PRIMARY KEY
станет кластеризованным индексом и уникальными ограничениями, не кластеризованными, но это поведение можно переопределить, указав CLUSTERED
или NONCLUSTERED
явно с объявлением ограничения (пример синтаксиса)
DECLARE @T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)
в результате вышеизложенного следующие индексы могут быть неявно созданы для табличных переменных в SQL Сервер 2000 - 2012.
+-------------------------------------+-------------------------------------+
| Index Type | Can be created on a table variable? |
+-------------------------------------+-------------------------------------+
| Unique Clustered Index | Yes |
| Nonunique Clustered Index | |
| Unique NCI on a heap | Yes |
| Non Unique NCI on a heap | |
| Unique NCI on a clustered index | Yes |
| Non Unique NCI on a clustered index | Yes |
+-------------------------------------+-------------------------------------+
последний требует некоторых объяснений. В определении переменной таблицы в начале этого ответа неуникальные некластеризованный индекс на Name
имитируется уникальный на Name,Id
(напомним, что SQL Server в любом случае молча добавит ключ кластеризованного индекса К не уникальному ключу NCI).
не уникальный кластеризованный индекс также может быть достигнут путем ручного добавления для действуйте как uniqueifier.
DECLARE @T TABLE
(
A INT NULL,
B INT NULL,
C INT NULL,
Uniqueifier INT NOT NULL IDENTITY(1,1),
UNIQUE CLUSTERED (A,Uniqueifier)
)
но это не точное моделирование того, как не уникальный кластеризованный индекс обычно будет реализован в SQL Server, поскольку это добавляет "Uniqueifier" ко всем строкам. Не только тех, кто этого требует.
следует понимать, что с точки зрения производительности нет различий между таблицами @temp и таблицами #temp, которые благоприятствуют переменным. Они находятся в одном и том же месте (tempdb) и реализуются одинаково. Все различия проявляются в дополнительных функциях. См. эту удивительно полную запись: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386
хотя там в случаях, когда временная таблица не может использоваться, например, в табличных или скалярных функциях, для большинства других случаев до v2016 (где даже отфильтрованные индексы могут быть добавлены в переменную таблицы) вы можете просто использовать таблицу #temp.
недостатком использования именованных индексов (или ограничений) в tempdb является то, что имена могут конфликтовать. Не только теоретически с другими процедурами, но часто довольно легко с другими экземплярами самой процедуры, которые попытались бы поместить тот же индекс на свою копию временная таблица.
чтобы избежать столкновения имен, обычно работает что-то вроде этого:
declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (@cmd);
это гарантирует, что имя всегда уникально даже между одновременными исполнениями одной и той же процедуры.