sql >> Database >  >> RDS >> Mysql

ENUM (opsomming) gegevenstype in MySQL:Top 12 feiten en handige tips

MySQL ENUM-gegevens zijn een tekenreeksgegevenstype met een waarde die is gekozen uit de lijst met toegestane waarden. U stelt deze toegestane waarden in tijdens het maken van de tabel, zoals hieronder weergegeven:

CREATE TABLE Product
(
    id int NOT NULL PRIMARY KEY,
    productName varchar(30) NOT NULL,
    color enum('blue','red','yellow','black','white') NOT NULL DEFAULT 'blue'
);

Makkelijk, nietwaar?

Om te beginnen is gegevensvalidatie direct zonder een andere tabel en een externe sleutel. In de strikte servermodus betekent dit dat u een verkeerde invoer niet kunt forceren. Dit is geweldig!

Of toch?

Zoals met alles in de wereld, is het niet altijd lang en gelukkig.

Na het lezen van de volgende 12 belangrijke feiten over MySQL ENUM, kunt u beslissen of het goed is voor uw volgende database of tabel in MySQL.

Voor dit artikel is de MySQL-versie 8.0.23 en de opslagengine InnoDB.

1. MySQL ENUM is een sleutel/tekenreekswaardepaartype

MySQL ENUM is een sleutel/waarde-paar. Waarden zijn tekenreeksen en sleutels zijn indexnummers.

Maar waar is de index?

MySQL wijst automatisch nummers toe zoals ze op uw lijst verschijnen. Dus of het nu gaat om een ​​shortlist van kleuren, klanttypes, begroetingen of betaalmethoden, er worden nummers toegekend. Dat is een vaste lijst die nooit zal uitbreiden. Bedenk 20 of minder items en waarden die nooit meer attributen zullen hebben. Anders heb je een tafel nodig.

Maar hoe worden deze indexen genummerd?

2. MySQL ENUM-index begint met 1 maar kan NULL of nul zijn

Ik zal beginnen met een voorbeeld.

CREATE TABLE people
(
  id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
  lastname varchar(30) NOT NULL,
  firstname varchar(30) NOT NULL,
  middlename varchar(30) NOT NULL,
  gender enum('Male','Female') NOT NULL DEFAULT 'Female',
  country enum('United States', 'Canada', 'Brazil', 
               'United Kingdom','Poland','Ukraine', 'Lithuania',  
               'Japan','Philippines','Thailand', 'Australia','New Zealand')  
              DEFAULT 'United States',
  modifieddate datetime NOT NULL DEFAULT NOW() 
);

Er zijn hier 2 MySQL ENUM-waarden: geslacht en land . Laat ik beginnen met het geslacht kolom die 2 waarden bevat:Man en Vrouw . De index voor Man is 1 en Vrouw is 2. Dit betekent dat sleutelindexen beginnen met 1.

Aan de hand van dit eenvoudige voorbeeld kunt u de index identificeren voor het land kolom. Het heeft 12 waarden. Het begint met de Verenigde Staten met een index van 1 en eindigt met Nieuw-Zeeland met een index van 12.

Opmerking :deze index verwijst niet naar de tabelindexen die we gebruiken voor snelle zoekopdrachten.

Naast deze getallen van 1 tot 65.535 kunnen ENUM-kolommen ook NULL of nul zijn. In ons voorbeeld is het land kolom accepteert NULL. Dus, afgezien van indexen 1 tot 12, is NULL een andere mogelijke index met een NULL-waarde.

U kunt ook een 0-index hebben. Dit gebeurt in de volgende situaties:

  • De servermodus voor uw MySQL is niet strikt.
  • Je voegt een waarde in die niet op de lijst met toegestane waarden staat.
  • Dan zal het invoegen lukken, maar de waarde is een lege string met een index van nul.

Gebruik altijd een strikte servermodus om fouten te voorkomen.

3. MySQL ENUM beperkt de mogelijke waarden in een kolom

In de strikte modus, het land kolom in ons eerder voorbeeld accepteert slechts 12 mogelijke waarden. Dus als u dit probeert, wordt de fout "Gegevens afgekapt voor kolom 'land'" gegenereerd:

INSERT INTO people (lastname, firstname, middlename, gender, country)
  VALUES ('Choi', 'Seungcheol', '','Male','South Korea');

De onderstaande foutmelding is opgetreden omdat Zuid-Korea niet op de opgesomde lijst staat.

De foutmelding is hetzelfde als in MySQL Workbench.

Als de hier gebruikte MySQL-server hoofdlettergevoelig is, wordt dit ook niet geaccepteerd:

INSERT INTO people (lastname, firstname, middlename, gender, country)
  VALUES ('Hemsworth', 'Chris', '', 'MALE', 'united states');

Waarom? We hebben het geslacht gedefinieerd als Man , niet MANNELIJK . En het land is Verenigde Staten , niet Verenigde Staten.

Uiteindelijk gedragen de opgesomde waarden in het MySQL ENUM-gegevenstype zich als beperkingen voor externe sleutels, maar zonder een andere tabel.

Afgezien hiervan is er nog een ander voordeel dat MySQL ENUM-gegevens bieden.

4. Vriendelijke output zonder het gebruik van JOIN

JOIN's zijn niet nodig, maar de uitvoer is vriendelijk. Laten we het onderstaande ENUM in MySQL-voorbeeld nemen om het uit te leggen:

SELECT * FROM people 
WHERE country = 4;

Met deze zoekopdracht worden mensen uit het Verenigd Koninkrijk opgehaald. Standaard zie je de strings die je hebt gedefinieerd in de ENUM-kolom. Maar intern worden de genummerde indexen opgeslagen. Dit is het resultaat:

Opmerking :De gegevens die u ziet, zijn gegenereerd met dbForge Studio voor de gegevensgenererende tool van MySQL. Ik heb 50.000 namen gegenereerd met de tool.

Ondertussen kan dezelfde output worden bereikt bij gebruik van een aparte tabel en een join.

SELECT
 p.id
,p.lastname
,p.firstname
,p.middlename
,CASE WHEN p.gender = 'M' THEN 'Male' ELSE 'Female' END AS gender
,c.countryname AS country
,p.modifieddate
FROM people_no_enums p
LEFT JOIN country c ON p.country = c.id
WHERE p.country = 4;

Dus, moet je MySQL ENUM gebruiken om JOINs helemaal te vermijden? Zeker niet! Dit is goed voor een kleine maar vaste lijst. Voor meer gegevens met een onbepaald aantal rijen en meer attributen is een tabel vereist. En om een ​​vriendelijkere output te maken zoals in figuur 2, heb je ook een JOIN nodig. Het hebben van een aparte tabel is flexibeler en vereist niets van de ontwikkelaar wanneer de gegevens live zijn. Dit is niet het geval bij Enumdatatype.

5. Filter MySQL-opsomming op index of tekenreekswaarde

In punt #4 zag je een voorbeeld met een WHERE-component om te filteren met een ENUM-kolom. Het gebruikte de index om het land te specificeren. Dit zal dus ook werken:

SELECT * from people
WHERE country IN (1,3,5)
AND gender = 1;

U kunt ook de tekenreekswaarde gebruiken, zoals hieronder:

SELECT * FROM people 
WHERE country='Philippines'
AND gender = 'Female';

6. Sorteren is op index

Sorteren kan een beetje lastig zijn. ENUM-waarden worden opgeslagen volgens hun indexnummer, niet de waarde. Bekijk de onderstaande code en de uitvoer die volgt in figuur 3.

SELECT DISTINCT 
 country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY country;

Als je wilt dat de sortering op waarde wordt gebaseerd, cast je de kolom naar een CHAR, zoals hieronder.

SELECT DISTINCT 
 country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CAST(country AS char);

Hoe zit het hiermee?

SELECT DISTINCT 
 country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CountryName;

Zo te zien wordt de waarde gebruikt om te sorteren. Maar dat is niet het geval. De output zal hetzelfde zijn als in figuur 3. ORDER BY met een CAST is de beste manier om op waarde te sorteren.

7. MySQL ENUM-opslag is maximaal 2 bytes

Volgens de officiële documentatie heeft de MySQL ENUM-standaardopslag betrekking op de index. De resulterende tabel is compacter in vergelijking met het opslaan van de waarden. Eén (1) byte voor opsommingen met 1 tot 255 mogelijke waarden. Twee (2) bytes voor 256 tot 65.535 mogelijke waarden.

Maar er is een geheim dat ik je wil vertellen.

Natuurlijk, als het om opslag gaat, zullen de waarden meer in beslag nemen dan de index. Aangezien een goed tafelontwerp een kleinere opbergruimte oplevert, gaan we een andere tafel maken met een aparte landelijke tafel.

CREATE TABLE country
(
   id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
   countryname varchar(30) NOT NULL,
   modifieddate datetime DEFAULT NOW()
);

CREATE TABLE people_no_enums
(
  id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
  lastname varchar(30) NOT NULL,
  firstname varchar(30) NOT NULL,
  middlename varchar(30) NOT NULL,
  gender char(1) not NULL,
  country tinyint DEFAULT 1,
  modifieddate datetime NOT NULL DEFAULT NOW() 
);

Laten we nu dezelfde gegevens invoegen.

INSERT INTO country (id, countryname, modifieddate)
  VALUES (1, 'United States', NOW()), (2, 'Canada', NOW()), (3, 'Brazil', NOW()), 
         (4, 'United Kingdom', NOW()), (5, 'Poland', NOW()), (6, 'Ukraine', NOW()), 
         (7, 'Lithuania', NOW()), (8, 'Japan', NOW()), (9, 'Philippines', NOW()), 
         (10, 'Thailand', NOW()), (11, 'Australia', NOW()), 
         (12, 'New Zealand', NOW());

INSERT INTO people_no_enums
SELECT
 p.id
,p.lastname
,p.firstname
,p.middlename
,CASE WHEN p.gender = 1 THEN 'M' ELSE 'F' END AS gender
,c.id
,p.modifieddate
FROM people p
LEFT JOIN country c ON p.country = c.countryname;

Hiervoor gebruiken we de tabel INFORMATION_SCHEMA.TABLES. Zie onderstaande code:

SELECT
table_name,
ROUND(((data_length + index_length)), 2) AS "Size in Bytes"
FROM information_schema.TABLES
WHERE table_schema = "testenumsdb"
AND TABLE_NAME LIKE 'people%'
ORDER BY (data_length + index_length) DESC;

Een genormaliseerde tabel zonder ENUM-kolommen in vergelijking met een tabel ermee vereist dezelfde grootte in bytes. Beide hebben 50.000 records met dezelfde naam met behulp van de InnoDB-opslagengine. Maar natuurlijk, het nieuwe land tafel zal ook ruimte innemen. U moet de andere voor- en nadelen van het gebruik van ENUM afwegen.

8. MySQL ENUM is alleen voor tekenreeksen

MySQL ENUM accepteert alleen letterlijke tekenreeksen. De onderstaande code werkt dus niet:

CREATE TABLE Product
(
   id int NOT NULL PRIMARY KEY,
   productName varchar(30),
   color enum('red','orange',CONCAT('red','orange'))
);

De CONCAT-functie binnen het Enumdatatype is niet toegestaan evenals andere geldige SQL-expressies.

9. MySQL ENUM kan niet opnieuw worden gebruikt

Vanaf dit punt zie je de donkere kant van MySQL ENUM.

Ten eerste kun je het niet opnieuw gebruiken. U moet dezelfde kleur-, grootte- en prioriteitsopsommingen dupliceren als u ze in een andere tabel nodig heeft. Een ontwerp zoals in figuur 6 hieronder is onmogelijk met ENUM's.

Om ENUM in de 2 bovenstaande tabellen te gebruiken, moet u de prioriteitenlijst op de 2 tabellen dupliceren.

10. Meer waarden toevoegen vereist een wijziging van de tabel

In het geslacht lijst eerder hebben we geprobeerd om slechts 2 items te gebruiken:Man en Vrouw . Wat als uw bedrijf besluit de LGBTQ te omarmen? U moet een ALTER TABLE uitvoeren en toevoegen aan het einde van de opsomming Lesbian , Homo , Biseksueel , Transgender , en Queer . Hier is de code:

ALTER TABLE people
   MODIFY COLUMN gender     
          enum('Male','Female','Lesbian','Gay','Bisexual','Transgender','Queer')     
          NOT NULL DEFAULT 'Male';

Dit draaien op mijn laptop met 50.000 records duurde slechts minder dan een seconde. Grotere en complexere tabellen zullen wat meer tijd in beslag nemen. Als de geslachtslijst een tabel is, hoeft u alleen de 5 nieuwe waarden in te voeren.

Voor het hernoemen van een waarde is ook ALTER TABLE nodig. Een aparte tabel vereist alleen een eenvoudig UPDATE-statement.

11. U kunt niet gemakkelijk mogelijke waarden opsommen

Vult u vervolgkeuzelijsten of gegroepeerde keuzerondjes in vanuit een tabel? Het is gemakkelijk als je een landelijke tafel hebt. Doe een SELECT id , landnaam UIT land , en u bent klaar om de vervolgkeuzelijst in te vullen.

Maar hoe doe je dit met MySQL ENUM?

Haal eerst de kolominformatie uit de INFORMATION_SCHEMA.COLUMNS tabel, zoals deze:

/* Get the possible values for country ENUM. */
SELECT  
 TABLE_NAME
,COLUMN_NAME
,COLUMN_TYPE
FROM information_schema.columns
WHERE TABLE_SCHEMA='testenumsdb'
  AND TABLE_NAME = 'people'
  AND COLUMN_NAME = 'country';

Vervolgens moet u die tekenreeks ontleden en formatteren voordat u een vervolgkeuzelijst vult. Best archaïsch, niet?

Maar er is nog een laatste ding.

12. MySQL ENUM is niet-standaard

ENUM is een MySQL-extensie op de ANSI SQL-standaard. Andere RDBMS-producten ondersteunen dit niet. Raadpleeg dus de juiste MySQL-zelfstudie voordat u met uw projecten begint. Als u bijvoorbeeld uw MySQL-database vol ENUM's naar SQL Server moet porten, moet u een tijdelijke oplossing gebruiken. Tijdelijke oplossingen zijn afhankelijk van hoe u de doeltabel in SQL Server ontwerpt.

Bottomline

U moet de voor- en nadelen van het gebruik van MySQL ENUM afwegen. Het hebben van een aparte tabel met de juiste normalisatie is het meest flexibel in de onzekere toekomst.

Extra punten zijn welkom. Ga dus naar het gedeelte Opmerkingen hieronder en vertel ons erover. Je kunt dit ook delen op je favoriete sociale mediaplatforms.


  1. Impact van de query_post_execution_showplan Extended Event in SQL Server 2012

  2. Hoe COUNT(*) prestaties op InnoDB te optimaliseren met behulp van index

  3. DISTINCT tellen over meerdere kolommen

  4. Hoe een script van SQL Server-gegevens te krijgen?