Створення індексу на змінній таблиці


190

Чи можете ви створити індекс на змінній таблиці в SQL Server 2000?

тобто

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

Чи можна створити індекс на Name?


3
Існує вартість створення обох типів тимчасових таблиць; і якщо у вас стільки даних, що вам потрібен індекс, можливо, час переглядати використання реальної таблиці; що ви налаштовані на безпеку транзакцій; фільтруйте за spid або ідентифікатором користувача, а потім очистіть його наприкінці. Реальні таблиці v temp таблиці мають як підйоми, так і падіння, але якщо продуктивність є проблемою; спробуйте також і справжній стіл.
u07ch

Тимчасова таблиця "IS" справжня таблиця, вона просто минає, коли ви закінчите. Справжня різниця (окрім того, що вона автоматично піде) полягає в тому, що вона знаходиться в TempDB. Це насправді величезно, якщо мова йде про індекси та обмеження, тому що ви можете зіткнутися з зіткненнями імен не тільки з іншими виконаннями вашого коду, але і з кодом, виконаним в інших базах даних у вашому екземплярі.
bielawski

@bielawski це змінна таблиця, а не темп. Змінні таблиці не дозволяють чітко назвати обмеження, імена, створені системою, гарантують унікальність. Вони дозволяють іменовані індекси з 2014 року, але це не проблема, оскільки індекси повинні бути однозначно названі в межах об'єкта, а не в межах об’єктів.
Мартін Сміт

Мій пункт був у 2 рази. 1) Окрім використання змінної, щоб уникнути заплутування транзакцій, між тимчасовою таблицею та змінною таблиці немає суттєвої різниці. Однак у V-2000 немає синтаксису для додавання обмежень, індексів ... до змінної. 2) З огляду на , можна використовувати тимчасову таблицю замість іменованих таблиць придатків як індекси БУДУТЬ зіткнення з одночасним виконуючими копіями одного і тим же SP , якщо використовуються ім'я статичного! Нижче наведений механізм був чітко розроблений, оскільки я відслідковував відмови SP у названих індексах, що стикаються під час цих точних обставин. Вони ОБОВ'ЯЗКОВО бути унікальними.
bielawski

1
@bielawski - Імена індексу не повинні бути унікальними між об'єктами - лише імена обмежень. це банально для перевірки. Просто виконуйCREATE TABLE #T1(X INT); CREATE TABLE #T2(X INT); CREATE INDEX IX ON #T1(X); CREATE INDEX IX ON #T2(X);
Мартін Сміт

Відповіді:


363

Питання позначено тегом 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 можуть або мати кластерний індекс, або структурувати як купи .

Кластеризовані індекси можуть бути оголошені як унікальні для заборони повторюваних значень ключа або за замовчуванням до не унікальних. Якщо не унікальний, то SQL Server мовчки додає унікальний код до будь-яких повторюваних ключів, щоб зробити їх унікальними.

Некластеризовані індекси також можуть бути явно оголошені унікальними. Інакше для не унікального випадку SQL Server додає локатор рядків (кластерний індексний ключ або RID для купи) до всіх індексних ключів (а не лише дублікатів), що ще раз гарантує їх унікальність.

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


1
Примітка: рішення 2000-2012 працює лише в тому випадку, якщо текстовий стовпець <= 900 байт. тобто. varchar (900), nvarchar (450)
Andre Figueiredo

1
@AndreFigueiredo так, це максимальний розмір для індексного ключа в постійних таблицях і в цих версіях.
Мартін Сміт

1
Я просто хотів зазначити, що відповідь SQL 2014 добре працює в Azure. Дякую Мартіне!
Jaxidian

13

Слід розуміти, що з точки зору продуктивності немає відмінностей між таблицями @temp та таблицями #temp, які надають перевагу змінним. Вони проживають там же (tempdb) і реалізуються однаково. Усі відмінності відображаються в додаткових функціях. Перегляньте цей надзвичайно повний запис: /dba/16385/whats-the-difference-bet between-a-temp-table-and-table-variable-in-sql-server/16386#16386

Хоча бувають випадки, коли таблицю тимчасових тем не можна використовувати, наприклад, у таблиці або скалярних функціях, для більшості інших випадків до v2016 (де навіть відфільтровані індекси можуть бути додані до змінної таблиці), ви можете просто використовувати таблицю #temp.

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

Щоб уникнути сутичок з іменами, щось подібне зазвичай працює:

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

Це гарантує, що ім’я завжди унікальне навіть між одночасним виконанням однієї і тієї ж процедури.


У нього є одна дужка, яка відсутня після varchar (40), додамо, що
Tejasvi Hegde

1
Проблеми з названими індексами не виникають - індекси мають бути однозначно названі в таблиці. Проблема полягає в іменованих обмеженнях, і найкраще рішення, як правило, не називати їх у тимчасових таблицях - іменовані обмеження запобігають кешування об'єктів таблиці темп.
Мартін Сміт

1
Це має бути правдою лише для певних версій (якщо це правда для будь-якої версії). Мені довелося придумати це рішення конкретно, тому що я виявив невдачі спалаху в зіткненні названих індексів під час одночасних виконання.
bielawski

@bielawski Ви використовуєте 2016 рік? Мені дуже цікаво, чи названі індекси на тимчасових таблицях є ризиком для одночасних середовищ.
Еласканатор

1
@Elaskanator так, вони є. Ми виявили суперечки в таблицях метаданих SQL, коли під навантаженням видалення імені індексу вирішило проблему. Це був SQL 2016.
Dan Def

0

Якщо змінна Таблиця має великі дані, то замість змінної таблиці (@table) створюйте temp 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);

створити індекс після оператора вставлення, щоб уникнути зайвого сортування
Boopathi.Indotnet

Зауважте, що це неможливо, якщо змінна таблиці функціонує
Geoff
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.