Dữ liệu MySQL ENUM là một kiểu dữ liệu chuỗi có giá trị được chọn từ danh sách các giá trị được phép. Bạn đặt các giá trị được phép này trong quá trình tạo bảng như hình dưới đây:
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'
);
Dễ dàng phải không?
Đối với người mới bắt đầu, việc xác thực dữ liệu diễn ra ngay lập tức mà không cần bảng khác và khóa ngoại. Trong chế độ máy chủ nghiêm ngặt, điều này có nghĩa là bạn không thể buộc nhập sai. Điều này thật tuyệt!
Hay là nó?
Giống như bất kỳ điều gì khác trên thế giới, nó không phải lúc nào cũng hạnh phúc mãi mãi.
Sau khi đọc 12 thông tin chính sau đây về MySQL ENUM, bạn có thể quyết định xem nó có tốt cho cơ sở dữ liệu hoặc bảng tiếp theo của bạn trong MySQL hay không.
Đối với bài viết này, phiên bản MySQL là 8.0.23 và công cụ lưu trữ là InnoDB.
1. MySQL ENUM là một loại cặp giá trị khóa / chuỗi
MySQL ENUM là một cặp khóa / giá trị. Giá trị là chuỗi và khóa là số chỉ mục.
Nhưng chỉ mục ở đâu?
MySQL tự động gán các số khi chúng xuất hiện trong danh sách của bạn. Vì vậy, cho dù đó là danh sách chọn lọc về màu sắc, loại khách hàng, cách chào hay phương thức thanh toán, các con số sẽ được chỉ định. Đó là danh sách cố định sẽ không bao giờ mở rộng. Hãy nghĩ về 20 mặt hàng và giá trị trở xuống sẽ không bao giờ có thêm thuộc tính. Nếu không, bạn cần một bảng.
Nhưng các chỉ mục này được đánh số như thế nào?
2. MySQL ENUM Index bắt đầu bằng 1 nhưng có thể là NULL hoặc Zero
Tôi sẽ bắt đầu với một ví dụ.
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()
);
Có 2 giá trị MySQL ENUM ở đây: giới tính và quốc gia . Hãy để tôi bắt đầu với giới tính cột chứa 2 giá trị: Nam và Nữ . Chỉ mục cho Nam là 1 và Nữ là 2. Điều này có nghĩa là các chỉ mục chính bắt đầu bằng 1.
Từ ví dụ đơn giản này, bạn có thể xác định chỉ số cho quốc gia cột. Nó có 12 giá trị. Nó bắt đầu với Hoa Kỳ với chỉ số 1 và kết thúc bằng New Zealand với chỉ số 12.
Lưu ý :chỉ mục này không tham chiếu đến các chỉ mục bảng mà chúng tôi sử dụng để tìm kiếm nhanh.
Bên cạnh các số này từ 1 đến 65,535, các cột ENUM cũng có thể là NULL hoặc không. Trong ví dụ của chúng tôi, quốc gia cột chấp nhận NULL. Vì vậy, ngoài các chỉ mục từ 1 đến 12, NULL là một chỉ mục khác có thể có giá trị NULL.
Bạn cũng có thể có một chỉ số 0. Điều này xảy ra trong các trường hợp sau:
- Chế độ máy chủ cho MySQL của bạn không nghiêm ngặt.
- Bạn chèn một giá trị không có trong danh sách các giá trị được phép.
- Khi đó, việc chèn sẽ thành công nhưng giá trị là một chuỗi rỗng với chỉ số bằng không.
Để tránh lỗi, hãy luôn sử dụng chế độ máy chủ nghiêm ngặt.
3. MySQL ENUM giới hạn các giá trị có thể có trong một cột
Dưới chế độ nghiêm ngặt, quốc gia trong ví dụ của chúng tôi trước đó sẽ chỉ chấp nhận 12 giá trị có thể. Vì vậy, nếu bạn cố gắng thực hiện việc này, lỗi "Dữ liệu bị cắt ngắn cho cột" country "" sẽ được đưa ra:
INSERT INTO people (lastname, firstname, middlename, gender, country)
VALUES ('Choi', 'Seungcheol', '','Male','South Korea');
Thông báo lỗi bên dưới xảy ra do Hàn Quốc không có trong danh sách được liệt kê.
Thông báo lỗi giống như trong MySQL Workbench.
Nếu Máy chủ MySQL được sử dụng ở đây có phân biệt chữ hoa chữ thường, thì điều này cũng sẽ không được chấp nhận:
INSERT INTO people (lastname, firstname, middlename, gender, country)
VALUES ('Hemsworth', 'Chris', '', 'MALE', 'united states');
Tại sao? Chúng tôi đã xác định giới tính là Nam , không phải MALE . Và quốc gia là Hoa Kỳ , không phải các quốc gia thống nhất.
Cuối cùng, các giá trị được liệt kê trong kiểu dữ liệu MySQL ENUM hoạt động giống như các ràng buộc khóa ngoại nhưng không có bảng khác.
Ngoài điều này, dữ liệu MySQL ENUM còn mang lại lợi ích khác.
4. Đầu ra thân thiện mà không cần sử dụng JOIN
Không cần JOIN, nhưng đầu ra thân thiện. Hãy lấy ENUM bên dưới trong ví dụ MySQL để giải thích nó:
SELECT * FROM people
WHERE country = 4;
Truy vấn này sẽ truy xuất những người từ Vương quốc Anh. Theo mặc định, bạn sẽ thấy các chuỗi bạn đã xác định trong cột ENUM. Nhưng bên trong, các chỉ mục được đánh số được lưu trữ. Đây là kết quả:
Lưu ý : Dữ liệu bạn thấy được tạo bằng cách sử dụng dbForge Studio dành cho công cụ tạo dữ liệu của MySQL. Tôi đã tạo 50.000 tên bằng công cụ này.
Trong khi đó, có thể đạt được cùng một đầu ra khi sử dụng một bảng riêng biệt và một phép nối.
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;
Vì vậy, bạn có nên sử dụng MySQL ENUM để tránh hoàn toàn các THAM GIA không? Chắc chắn không phải! Điều này là tốt cho một danh sách nhỏ nhưng cố định. Nhiều dữ liệu hơn với số lượng hàng không xác định và nhiều thuộc tính hơn yêu cầu một bảng. Và để tạo ra một đầu ra thân thiện hơn như trong Hình 2, bạn cũng sẽ cần một JOIN. Việc có một bảng riêng linh hoạt hơn và không cần nhà phát triển yêu cầu gì khi dữ liệu đang hoạt động. Đây không phải là trường hợp của Enumdatatype.
5. Lọc kiểu liệt kê MySQL theo chỉ mục hoặc giá trị chuỗi
Trong điểm # 4, bạn đã thấy một ví dụ với mệnh đề WHERE để lọc bằng cột ENUM. Nó sử dụng chỉ mục để chỉ định quốc gia. Vì vậy, điều này cũng sẽ hoạt động:
SELECT * from people
WHERE country IN (1,3,5)
AND gender = 1;
Bạn cũng có thể sử dụng giá trị chuỗi, như giá trị bên dưới:
SELECT * FROM people
WHERE country='Philippines'
AND gender = 'Female';
6. Sắp xếp theo Chỉ mục
Việc sắp xếp có thể hơi phức tạp. Các giá trị ENUM được lưu trữ theo số chỉ mục của chúng, không phải theo giá trị. Kiểm tra mã bên dưới và kết quả sau trong Hình 3.
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY country;
Nếu bạn muốn sắp xếp dựa trên giá trị, hãy truyền cột thành CHAR, giống như cột bên dưới.
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CAST(country AS char);
Còn cái này thì sao?
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CountryName;
Từ giao diện của nó, giá trị sẽ được sử dụng để sắp xếp. Nhưng đó không phải là trường hợp. Đầu ra sẽ giống như trong Hình 3. ORDER BY với CAST là cách tốt nhất để sắp xếp theo giá trị.
7. Bộ nhớ MySQL ENUM Chỉ tối đa 2 byte
Theo tài liệu chính thức, bộ lưu trữ mặc định MySQL ENUM liên quan đến chỉ mục. Bảng kết quả nhỏ gọn hơn so với việc lưu trữ các giá trị. Một (1) byte cho các kiểu liệt kê có từ 1 đến 255 giá trị có thể. Hai (2) byte cho 256 đến 65,535 giá trị có thể.
Nhưng có một bí mật tôi muốn nói với bạn.
Tất nhiên, khi lưu trữ được quan tâm, các giá trị sẽ chiếm nhiều hơn chỉ mục. Vì thiết kế bảng thích hợp tạo ra diện tích lưu trữ nhỏ hơn, hãy tạo một bảng khác với bảng quốc gia riêng biệt.
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()
);
Bây giờ, hãy chèn cùng một dữ liệu.
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;
Để làm điều đó, chúng tôi sử dụng bảng INFORMATION_SCHEMA.TABLES. Xem mã bên dưới:
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;
Một bảng chuẩn hóa không có cột ENUM so với một bảng có nó yêu cầu cùng kích thước tính bằng byte. Cả hai đều có 50.000 bản ghi cùng tên bằng cách sử dụng công cụ lưu trữ InnoDB. Nhưng tất nhiên, quốc gia mới bảng cũng sẽ chiếm không gian. Bạn cần cân nhắc những ưu và nhược điểm khác của việc sử dụng ENUM.
8. MySQL ENUM Chỉ dành cho String Literals
MySQL ENUM chỉ chấp nhận các ký tự chuỗi. Vì vậy, mã bên dưới sẽ không hoạt động:
CREATE TABLE Product
(
id int NOT NULL PRIMARY KEY,
productName varchar(30),
color enum('red','orange',CONCAT('red','orange'))
);
Hàm CONCAT bên trong Enumdatatype không được phép cũng như các biểu thức SQL hợp lệ khác.
9. MySQL ENUM không thể được sử dụng lại
Từ điểm này, bạn sẽ thấy mặt tối của MySQL ENUM.
Đầu tiên, bạn không thể sử dụng lại nó. Bạn sẽ phải sao chép cùng một màu sắc, kích thước và các bảng liệt kê ưu tiên nếu bạn cần chúng trong một bảng khác. Một thiết kế như trong Hình 6 dưới đây là không thể với ENUM.
Để sử dụng ENUM trong 2 bảng trên, bạn cần sao chép danh sách ưu tiên trên 2 bảng.
10. Thêm nhiều giá trị hơn yêu cầu thay đổi bảng
Trong giới tính danh sách trước đó, chúng tôi đã cố gắng chỉ sử dụng 2 mục: Nam và Nữ . Điều gì sẽ xảy ra nếu công ty của bạn quyết định chấp nhận LGBTQ? Bạn cần chạy ALTER TABLE và thêm vào cuối bảng liệt kê Lesbian , Đồng tính nam , Lưỡng tính , Người chuyển giới và Queer . Đây là mã:
ALTER TABLE people
MODIFY COLUMN gender
enum('Male','Female','Lesbian','Gay','Bisexual','Transgender','Queer')
NOT NULL DEFAULT 'Male';
Việc chạy điều này trên máy tính xách tay của tôi với 50.000 bản ghi chỉ mất chưa đầy một giây. Các bảng lớn hơn và phức tạp hơn sẽ tiêu tốn nhiều thời gian hơn một chút. Nếu danh sách giới tính là một bảng, tất cả những gì bạn cần là chèn 5 giá trị mới.
Đổi tên một giá trị cũng sẽ cần ALTER TABLE. Một bảng riêng biệt chỉ yêu cầu câu lệnh CẬP NHẬT dễ dàng.
11. Bạn không thể dễ dàng liệt kê ra các giá trị có thể có
Bạn có điền danh sách thả xuống hoặc các nút radio được nhóm từ một bảng không? Thật dễ dàng khi bạn có một bảng quốc gia. Thực hiện một id CHỌN , tên quốc gia TỪ quốc gia và bạn đã sẵn sàng để điền danh sách thả xuống.
Nhưng bạn sẽ làm điều này như thế nào với MySQL ENUM?
Đầu tiên, lấy thông tin cột từ bảng INFORMATION_SCHEMA.COLUMNS, như sau:
/* 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';
Sau đó, bạn phải phân tích cú pháp và định dạng chuỗi đó trước khi điền vào danh sách thả xuống. Khá cổ điển phải không?
Nhưng còn một điều cuối cùng.
12. MySQL ENUM không phải là tiêu chuẩn
ENUM là một phần mở rộng của MySQL theo tiêu chuẩn ANSI SQL. Các sản phẩm RDBMS khác không hỗ trợ điều này. Vì vậy, hãy tham khảo hướng dẫn MySQL thích hợp trước khi bắt đầu các dự án của bạn. Ví dụ:nếu bạn cần chuyển cơ sở dữ liệu MySQL đầy ENUM sang SQL Server, bạn cần thực hiện một giải pháp khác. Các giải pháp thay thế sẽ khác nhau tùy thuộc vào cách bạn thiết kế bảng đích trong SQL Server.
Tóm tắt
Bạn phải cân nhắc những ưu và nhược điểm của việc sử dụng MySQL ENUM. Có một bảng riêng biệt được áp dụng chuẩn hóa thích hợp là cách linh hoạt nhất trong tương lai không chắc chắn.
Chúng tôi hoan nghênh các điểm bổ sung. Vì vậy, hãy đi đến phần Nhận xét bên dưới và cho chúng tôi biết về điều đó. Bạn cũng có thể chia sẻ điều này trên các nền tảng truyền thông xã hội yêu thích của mình.