Создание индекса по табличной переменной - PullRequest
175 голосов
/ 20 мая 2009

Можете ли вы создать index для табличной переменной в SQL Server 2000?

т.е.

DECLARE @TEMPTABLE TABLE (
        [ID] [int] NOT NULL PRIMARY KEY
        ,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL 
)

Могу ли я создать индекс по имени?

Ответы [ 3 ]

329 голосов
/ 30 июня 2013

Вопрос помечен 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 могут иметь кластеризованный индекс или иметь структуру heaps .

Кластерные индексы могут быть объявлены как уникальные, чтобы запретить повторяющиеся значения ключей, или по умолчанию не уникальные. Если не уникальный, то SQL Server автоматически добавляет uniqueifier к любым дублирующимся ключам, чтобы сделать их уникальными.

Некластеризованные индексы также могут быть явно объявлены как уникальные. В противном случае для неуникального случая SQL Server добавляет локатор строк (ключ кластеризованного индекса или RID для кучи) ко всем ключам индекса (а не только к дубликатам), что снова гарантирует их уникальность.

В SQL Server 2000 - 2012 индексы для табличных переменных можно неявно создавать только путем создания ограничения UNIQUE или PRIMARY KEY. Разница между этими типами ограничений заключается в том, что первичный ключ должен находиться в столбцах, которые не могут содержать значения NULL. Столбцы, участвующие в уникальном ограничении, могут иметь значение NULL. (хотя реализация 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 Server 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.

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

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, так как это добавляет «уникализатор» ко всем строкам. Не только те, которые в этом нуждаются.

12 голосов
/ 14 июня 2016

Следует понимать, что с точки зрения производительности нет различий между таблицами @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 (когда к табличной переменной можно добавить даже отфильтрованные индексы), вы можете просто использовать # временная таблица.

Недостатком использования именованных индексов (или ограничений) в базе данных tempdb является то, что имена могут затем конфликтовать. Не только теоретически с другими процедурами, но часто довольно легко с другими экземплярами самой процедуры, которая будет пытаться поместить тот же индекс в свою копию таблицы #temp.

Чтобы избежать конфликтов имен, обычно работает что-то вроде этого:

declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (@cmd);

Это гарантирует, что имя всегда уникально даже при одновременном выполнении одной и той же процедуры.

0 голосов
/ 24 мая 2019

Если переменная Table содержит большие данные, то вместо табличной переменной (@table) создать временную таблицу (#table) .table переменная не позволяет создавать индекс после вставки.

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. Создать таблицу с уникальным кластеризованным индексом

  2. Вставить данные в таблицу Temp "#Table"

  3. Создание некластеризованных индексов.

     CREATE NONCLUSTERED INDEX IX1  ON #Table (C2,C3);
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...