sql >> Databasteknik >  >> RDS >> Mysql

MySQL varchar indexlängd

September 2021 edit:Jag har använt MySQL 8.0 i ett par år nu, så här är lite uppdaterad information.

MySQL-manualen har nu en mycket informativ sida angående konvertering mellan utf8mb3 (för närvarande även känd som utf8 ) och utf8mb4 . utf8mb3 är utfasad och kommer att tas bort så småningom; och när den tas bort, dess nuvarande alias, utf8 , kommer att hänvisa till utf8mb4 istället.

Med utfasad utf8mb3 , kan du lagra upp till 255 tecken i ett index, medan med utf8mb4 , upp till 191, när du använder COMPACT eller REDUNDANT radformat.

Med COMPRESSED eller DYNAMIC radformat, indexnyckelprefix kan vara upp till 3072 byte. Med dem kan du indexera upp till 1024 tecken för utf8mb3 , och 768 tecken för utf8mb4 .

Nedan är mitt tidigare svar, som förklarar en del av logiken bakom antalet tecken du kan indexera mot antalet byte .

Jag måste revidera mitt svar på grund av min forskning. Jag skrev ursprungligen detta (citerar mig själv):

Jag tror att svaret är att du inte kan veta hur många tecken som kommer att finnas i indexet eftersom du inte kan veta hur många byte dina tecken kommer att vara (såvida du inte gör något för att utesluta flerbytetecken).

Och jag är inte säker, men det kanske fortfarande är korrekt, men inte riktigt som jag tänkt mig.

Här är det korrekta svaret:

MySQL förutsätter 3 byte per utf8-tecken. 255 tecken är den maximala indexstorleken du kan ange per kolumn, eftersom 256x3=768, vilket bryter mot gränsen på 767 byte.

Om du inte anger indexstorlek väljer MySQL den maximala storleken (dvs. 255 per kolumn). En UNIK begränsning kan inte läggas på en utf8-kolumn vars längd är större än 255, eftersom ett unikt index måste innehålla hela cellvärdet. Men ett vanligt index kan användas - det kommer bara att indexera de första 255 tecknen (eller de första 767 byten?). Och det är där det fortfarande finns en del mysterium för mig.

MySTERY:Jag kan se varför MySQL antar 3 byte per tecken, för säkerhets skull, för annars kan den UNIKA begränsningen brytas. Men dokumenten tycks antyda att indexet faktiskt är dimensionerat i byte, inte tecken. Så anta att du sätter en 255 char (765 byte) index på en varchar(256 ) kolumn. Om tecknen du lagrar alla är ASCII, 1-byte-tecken, som A-Z, a-z, 0-9, då kan du passa in hela kolumnen i 767 byte-indexet. Och det verkar som att det är vad som faktiskt skulle hända.

Nedan finns lite mer information från mitt ursprungliga svar om tecken, byte, etc.

Enligt wikipedia , UTF-8-tecken kan vara 1,2, 3 eller 4 byte långa. Men enligt denna mysql-dokumentation , den maximala teckenstorleken är 3 byte, så alla kolumnindexindex över 255 tecken kan nå den bytegränsen. Men som jag förstår det kanske det inte är det. Om de flesta av dina tecken är i ASCII-intervallet kommer din genomsnittliga teckenstorlek att vara närmare 1 byte. Om din genomsnittliga teckenstorlek till exempel är 1,3 byte (mest 1 byte, men ett betydande antal 2-3 byte tecken), kan du ange ett index på 767/1,3

Så, om du lagrar mestadels 1-byte-tecken, skulle din faktiska teckengräns vara mer som:767 / 1.3 =590. Men det visar sig att det inte är så det fungerar. 255 tecken är gränsen.

Som nämnts i denna MySQL-dokumentation ,

Prefixgränser mäts i byte, medan prefixlängden i CREATE INDEX-satser tolkas som antal tecken för icke-binära datatyper (CHAR, VARCHAR, TEXT). Ta hänsyn till detta när du anger en prefixlängd för en kolumn som använder en uppsättning av flera bytecken.

Det verkar som att MySQL råder folk att göra en beräkning/uppskattning som jag just gjorde för att bestämma din nyckelstorlek för en varchar-kolumn. Men du kan faktiskt inte ange ett index som är större än 255 för utf8-kolumner.

Slutligen, om du hänvisar tillbaka till min andra länk igen, finns det också detta:

När konfigurationsalternativet innodb_large_prefix är aktiverat höjs denna längdgräns till 3072 byte för InnoDB-tabeller som använder radformaten DYNAMIC och COMPRESSED.

Så det verkar som att du kan få mycket större index om du vill, med lite justeringar. Se bara till att radformaten är DYNAMISKA eller KOMPRESSERADE. Du kan förmodligen ange ett index på 1023 eller 1024 tecken i så fall.

Förresten, det visar sig att du kan lagra 4-byte-tecken med hjälp av [utf8mb4-teckenuppsättningen][4]. Utf8-teckenuppsättningen lagrar tydligen endast ["plane 0"-tecken][5].

EDIT:

Jag försökte precis skapa ett sammansatt index på en varchar(511) kolumn med en tinyint(1) kolumn och fick felmeddelandet som säger att den maximala indexstorleken var 767 byte. Detta får mig att tro att MySQL antar att utf8 teckenuppsättningskolumner kommer att innehålla 3 byte per tecken (maximalt), och låter dig använda max 255 tecken. Men det är kanske bara med sammansatta index. Jag kommer att uppdatera mitt svar när jag får reda på mer. Men för tillfället lämnar jag detta som en redigering.



  1. Hur SIN() fungerar i MariaDB

  2. Bästa sättet att ta bort miljontals rader efter ID

  3. Hur timeofday() fungerar i PostgreSQL

  4. Count(*) vs Count(1) - SQL Server