Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Obejście maksymalnego limitu kolumn SQL Server 1024 i 8kb rozmiaru rekordu

To po prostu niemożliwe. Zobacz Wewnątrz Silnik pamięci masowej:anatomia rekordu

Zakładając, że Twój stół wygląda mniej więcej tak.

CREATE TABLE T1(
    col_1 varchar(8000) NULL,
    col_2 varchar(8000) NULL,
    /*....*/
    col_999 varchar(8000) NULL,
    col_1000 varchar(8000) NULL
) 

Wtedy nawet wiersz ze wszystkimi NULL wartości będą używać następującej pamięci.

  • 1 bajtowe bity stanu A
  • 1 bajtowe bity stanu B
  • Przesunięcie liczby kolumn o 2 bajty
  • 125 bajtów NULL_BITMAP (1 bit za kolumnę dla 1000 kolumn)

To jest gwarantowane 129 bajtów już zużytych (pozostawiając 7931).

Jeśli którakolwiek z kolumn ma wartość inną niż NULL lub pusty ciąg, potrzebujesz również miejsca na

  • Liczba kolumn o zmiennej długości 2 bajty (pozostawiając 7929).
  • Wszędzie od 2 do 2000 bajtów dla tablicy przesunięć kolumn.
  • Samych danych.

Tablica przesunięcia kolumny zajmuje 2 bajty na kolumnę o zmiennej długości z wyjątkiem jeśli ta kolumna i wszystkie późniejsze kolumny mają również zerową długość. Aktualizuję więc col_1000 wymusiłoby użycie całych 2000 bajtów podczas aktualizowania col_1 użyje tylko 2 bajtów.

Możesz więc wypełnić każdą kolumnę 5 bajtami danych, a biorąc pod uwagę 2 bajty w tablicy przesunięć kolumn, można dodać do 7000 bajtów, co mieści się w pozostałych 7929 bajtach.

Jednak dane, które przechowujesz mają 102 bajty (51 nvarchar znaków), więc może to być przechowywane poza wierszem z 24-bajtowym wskaźnikiem do rzeczywistych danych pozostałych w wierszu.

FLOOR(7929/(24 + 2)) = 304

Najlepszym przypadkiem byłoby więc przechowywanie 304 kolumn o tej długości danych i to jest, jeśli aktualizujesz z col_1 , col_2 , ... . Jeśli col_1000 zawiera dane, to obliczenie jest

FLOOR(5929/24) = 247

Dla NTEXT obliczenia są podobne, z tym wyjątkiem, że może używać 16-bajtowego wskaźnika co pozwoliłoby na ściśnięcie danych w kilku dodatkowych kolumnach

FLOOR(7929/(16 + 2)) = 440

Konieczność podążania za wszystkimi tymi wskaźnikami poza wierszami dla każdego SELECT w stosunku do tabeli prawdopodobnie bardzo zaszkodziłoby wydajności.

Skrypt do testowania

DROP TABLE T1

/* Create table with 1000 columns*/
DECLARE @CreateTableScript nvarchar(max) = 'CREATE TABLE T1('

SELECT @CreateTableScript += 'col_' + LTRIM(number) + ' VARCHAR(8000),'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 1000
ORDER BY number

SELECT @CreateTableScript += ')'

EXEC(@CreateTableScript)

/* Insert single row with all NULL*/
INSERT INTO T1 DEFAULT VALUES


/*Updating first 304 cols succeed. Change to 305 and it fails*/
DECLARE @UpdateTableScript nvarchar(max) = 'UPDATE T1 SET  '

SELECT @UpdateTableScript += 'col_' + LTRIM(number) + ' = REPLICATE(1,1000),'
FROM master..spt_values
WHERE type='P' AND number BETWEEN 1 AND 304
ORDER BY number

SET @UpdateTableScript = LEFT(@UpdateTableScript,LEN(@UpdateTableScript)-1)
EXEC(@UpdateTableScript)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy każdy klucz obcy SQL Server powinien mieć pasujący indeks?

  2. Data i godzina programu SQL Server PODOBNY wybór?

  3. 11 sposobów na odzyskanie klucza podstawowego w SQL Server (przykłady T-SQL)

  4. Aktualizuj dane za pomocą funkcji o wartościach przechowywanych w tabeli w SQL Server

  5. 7 sposobów na zwrócenie wszystkich tabel z kluczami obcymi w SQL Server