MySQL ENUM данните са низов тип данни със стойност, избрана от списъка с разрешени стойности. Вие задавате тези разрешени стойности по време на създаването на таблицата, както е показано по-долу:
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'
);
Лесно, нали?
Като за начало, валидирането на данните е моментално без друга таблица и външен ключ. При строг сървърен режим това означава, че не можете да наложите грешен вход. Това е страхотно!
Или е така?
Както всяко друго нещо на света, това не винаги е щастливо.
След като прочетете следните 12 ключови факта за MySQL ENUM, можете да решите дали е добър за следващата ви база данни или таблица в MySQL.
За тази статия версията на MySQL е 8.0.23, а машината за съхранение е InnoDB.
1. MySQL ENUM е тип двойка ключ/низова стойност
MySQL ENUM е двойка ключ/стойност. Стойностите са низове, а ключовете са индексни числа.
Но къде е индексът?
MySQL автоматично присвоява номера, както се появяват във вашия списък. Така че, независимо дали става въпрос за кратък списък с цветове, типове клиенти, поздрави или начини на плащане, номерата ще бъдат присвоени. Това е фиксиран списък, който никога няма да се разшири. Помислете за 20 или по-малко елемента и стойности, които никога няма да имат допълнителни атрибути. В противен случай имате нужда от маса.
Но как са номерирани тези индекси?
2. MySQL ENUM индекс започва с 1, но може да бъде NULL или нула
Ще започна с пример.
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()
);
Тук има 2 стойности на MySQL ENUM: пол и държава . Нека започна с пол колона, която съдържа 2 стойности:Мъжки и Женски . Индексът за Мъжки е 1 и Женски е 2. Това означава, че ключовите индекси започват с 1.
От този прост пример можете да идентифицирате индекса за държавата колона. Има 12 стойности. Започва със САЩ с индекс 1 и завършва с Нова Зеландия с индекс 12.
Забележка :този индекс не се отнася до индексите на таблицата, които използваме за бързо търсене.
Освен тези числа от 1 до 65 535, ENUM колоните могат също да бъдат NULL или нула. В нашия пример държавата колона приема NULL. Така че, освен индекси от 1 до 12, NULL е друг възможен индекс със стойност NULL.
Можете също да имате индекс 0. Това се случва в следните ситуации:
- Режимът на сървъра за вашия MySQL не е строг.
- Вмъквате стойност, която не е в списъка с разрешени стойности.
- След това вмъкването ще бъде успешно, но стойността е празен низ с индекс нула.
За да избегнете грешки, винаги използвайте строг сървърен режим.
3. MySQL ENUM ограничава възможните стойности в колона
При строг режим държавата колона в нашия пример по-рано ще приеме само 12 възможни стойности. Така че, ако се опитате да направите това, ще бъде изведена грешката „Данните са съкратени за колона „държава““:
INSERT INTO people (lastname, firstname, middlename, gender, country)
VALUES ('Choi', 'Seungcheol', '','Male','South Korea');
Съобщението за грешка по-долу се появи, защото Южна Корея не е в изброения списък.
Съобщението за грешка е същото като в MySQL Workbench.
Ако използваният тук MySQL сървър е чувствителен към малки и големи букви, това също няма да бъде прието:
INSERT INTO people (lastname, firstname, middlename, gender, country)
VALUES ('Hemsworth', 'Chris', '', 'MALE', 'united states');
Защо? Определихме пола като Мъжки , а не МЪЖ . И страната е Съединените щати , а не съединените щати.
В крайна сметка изброените стойности в типа данни на MySQL ENUM действат като ограничения на външния ключ, но без друга таблица.
Освен това, има и друго предимство, което предоставят данните от MySQL ENUM.
4. Удобен изход без използване на JOIN
Няма нужда от JOIN, но изходът е приятелски настроен. Нека вземем примера по-долу ENUM в MySQL, за да го обясним:
SELECT * FROM people
WHERE country = 4;
Тази заявка ще извлече хора от Обединеното кралство. По подразбиране виждате низовете, които сте дефинирали в колоната ENUM. Но вътрешно, номерираните индекси се съхраняват. Ето резултата:
Забележка :Данните, които виждате, са генерирани с помощта на dbForge Studio за инструмента за генериране на данни на MySQL. С помощта на инструмента генерирах 50 000 имена.
Междувременно същият резултат може да се постигне, когато се използва отделна таблица и обединяване.
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;
И така, трябва ли да използвате MySQL ENUM, за да избегнете напълно JOIN? Определено не! Това е добре за малък, но фиксиран списък. Повече данни с неопределен брой редове и повече атрибути изисква таблица. И за да направите по-удобен изход като на фигура 2, ще ви трябва и JOIN. Наличието на отделна таблица е по-гъвкаво и не изисква нищо от разработчика, когато данните са активни. Това не е така с Enumdatatype.
5. Филтрирайте изброяването на MySQL по индекс или стойност на низ
В точка #4 видяхте пример с клауза WHERE за филтриране с ENUM колона. Той използва индекса, за да посочи държавата. Така че, това също ще работи:
SELECT * from people
WHERE country IN (1,3,5)
AND gender = 1;
Можете също да използвате стойността на низа, като тази по-долу:
SELECT * FROM people
WHERE country='Philippines'
AND gender = 'Female';
6. Сортирането е по индекс
Сортирането може да бъде малко сложно. Стойностите на ENUM се съхраняват според техните индексни номера, а не стойността. Вижте кода по-долу и изхода, който следва на фигура 3.
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY country;
Ако искате сортирането да се основава на стойност, прехвърлете колоната към CHAR, като този по-долу.
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CAST(country AS char);
Какво ще кажете за това?
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CountryName;
Както изглежда, стойността ще се използва за сортиране. Но това не е така. Резултатът ще бъде същият като на фигура 3. ORDER BY с CAST е най-добрият начин за сортиране по стойност.
7. MySQL ENUM Storage е само до 2 байта
Според официалната документация хранилището по подразбиране на MySQL ENUM включва индекса. Получената таблица е по-компактна в сравнение със съхраняването на стойностите. Един (1) байт за изброявания с 1 до 255 възможни стойности. Два (2) байта за 256 до 65 535 възможни стойности.
Но има една тайна, която искам да ви кажа.
Разбира се, когато става въпрос за съхранение, стойностите ще заемат повече от индекса. Тъй като правилният дизайн на масата създава по-малък отпечатък за съхранение, нека създадем друга маса с отделна таблица за страната.
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()
);
Сега нека вмъкнем същите данни.
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;
За да направим това, използваме таблицата INFORMATION_SCHEMA.TABLES. Вижте кода по-долу:
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;
Нормализирана таблица без ENUM колони в сравнение с таблица с нея изисква същия размер в байтове. И двете имат по 50 000 записа с едни и същи имена, използващи механизма за съхранение на InnoDB. Но разбира се, новата държава масата също ще заема място. Трябва да прецените другите предимства и недостатъци на използването на ENUM.
8. MySQL ENUM е само за низови литерали
MySQL ENUM приема само низови литерали. Така че кодът по-долу няма да работи:
CREATE TABLE Product
(
id int NOT NULL PRIMARY KEY,
productName varchar(30),
color enum('red','orange',CONCAT('red','orange'))
);
Функцията CONCAT вътре в Enumdatatype не е разрешена както и други валидни SQL изрази.
9. MySQL ENUM не може да се използва повторно
От този момент ще видите тъмната страна на MySQL ENUM.
Първо, не можете да го използвате повторно. Ще трябва да дублирате изброяванията със същия цвят, размер и приоритет, ако имате нужда от тях в друга таблица. Дизайн като този на фигура 6 по-долу е невъзможен с ENUM.
За да използвате ENUM в двете таблици по-горе, трябва да дублирате списъка с приоритети в двете таблици.
10. Добавянето на повече стойности изисква промяна на таблицата
В пол списък по-рано, ние се опитахме да използваме само 2 елемента:Мъжки и Женски . Ами ако вашата компания реши да приеме ЛГБТК? Трябва да стартирате ALTER TABLE и да добавите в края на изброяването Lesbian , Гей , Бисексуални , Транссексуален , и Queer . Ето кода:
ALTER TABLE people
MODIFY COLUMN gender
enum('Male','Female','Lesbian','Gay','Bisexual','Transgender','Queer')
NOT NULL DEFAULT 'Male';
Изпълнението на това на моя лаптоп с 50 000 записа отне само по-малко от секунда. По-големите и по-сложни таблици ще отнемат малко повече време. Ако списъкът с пол е таблица, всичко, което трябва, е да вмъкнете 5-те нови стойности.
Преименуването на стойност също ще изисква ALTER TABLE. Отделна таблица изисква само лесен оператор UPDATE.
11. Не можете лесно да изброите възможните стойности
Попълвате ли падащи списъци или групирани радио бутони от таблица? Лесно е, когато имате селска маса. Направете SELECT идентификатор , име на държава ОТ държава , и сте готови да попълните падащия списък.
Но как ще направите това с MySQL ENUM?
Първо вземете информацията за колоните от таблицата INFORMATION_SCHEMA.COLUMNS, както следва:
/* 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';
След това трябва да анализирате този низ и да го форматирате, преди да попълните падащ списък. Доста архаично, нали?
Но има едно последно нещо.
12. MySQL ENUM е Нестандартен
ENUM е разширение на MySQL към стандарта ANSI SQL. Други RDBMS продукти не поддържат това. Така че, вижте подходящия урок за MySQL, преди да започнете вашите проекти. Ако трябва да пренесете вашата MySQL база данни, пълна с ENUM, към SQL Server, например, трябва да направите заобиколно решение. Заобиколните решения ще варират в зависимост от това как проектирате целевата таблица в SQL Server.
Долен ред
Трябва да прецените плюсовете и минусите на използването на MySQL ENUM. Наличието на отделна таблица с приложимо правилно нормализиране е най-гъвкавото в несигурното бъдеще.
Приветстваме допълнителни точки. Така че, отидете в секцията за коментари по-долу и ни разкажете за това. Можете също да споделите това в любимите си социални медийни платформи.