Cách này cũng không phổ biến:
SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.uid IS NULL;
LEFT JOIN hoạt động trên cơ sở khi s1.rank ở giá trị lớn nhất, không có s2.rank nào có giá trị lớn hơn và các giá trị của hàng s2 sẽ là NULL.
Nhưng tôi muốn nói rằng cách làm của bạn là cách làm phổ biến nhất, dễ hiểu nhất, vâng.
CHỈNH SỬA:Về câu hỏi tại sao đôi khi chậm hơn:
Hiệu suất của truy vấn này phụ thuộc vào "cách nó được viết cẩn thận". Lấy dữ liệu của bạn làm ví dụ:
drop table if exists students;
CREATE TABLE students
(`uid` bigint, `last_name` varchar(5), `first_name` varchar(8), `dob` varchar(10), `email` varchar(16), `rank` int, `grade` int)
;
INSERT INTO students
(`uid`, `last_name`, `first_name`, `dob`, `email`, `rank`, `grade`)
VALUES
(13428700000001, 'Smith', 'John', '1990-12-03', '[email protected]', 99, 4),
(13428721960000, 'Li', 'Kai Li', '1979-02-15', '[email protected]', 12, 2),
(13428722180001, 'Zhang', 'Xi Xiong', '1993-11-09', '[email protected]', 5, 5),
(13428739950000, 'Zhou', 'Ji Hai', '1991-06-06', '[email protected]', 234, 1),
(13428739950001, 'Pan', 'Yao', '1992-05-12', '[email protected]', 43, 2),
(13428740010001, 'Jin', 'Denny', '1994-06-02', '[email protected]', 198, 3),
(13428740010002, 'Li', 'Fonzie', '1991-02-02', '[email protected]', 75, 3),
(13428743370000, 'Ma', 'Haggar', '1991-08-16', '[email protected]', 47, 4),
(13428743590001, 'Ren', 'Jenny', '1990-03-29', '[email protected]', 5, 2),
(13428774040000, 'Chen', 'Dragon', '1999-04-12', '[email protected]', 23, 5),
(13428774260001, 'Wang', 'Doctor', '1996-09-30', '[email protected]', 1, 5),
(13430100000000, 'Chanz', 'Heyvery', '1994-04-04', '[email protected]', 107, 2)
;
Giải thích cho truy vấn của bạn trông giống như sau:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
-------------------------------------------------------------------------------------------------------
| 1 | PRIMARY | students | ALL | (null) | (null) | (null) | (null) | 12 | Using where |
| 2 | SUBQUERY | students | ALL | (null) | (null) | (null) | (null) | 12 | |
Câu hỏi từ truy vấn của tôi như thế này:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
----------------------------------------------------------------------------------------------------
| 1 | SIMPLE | s1 | ALL | (null) | (null) | (null) | (null) | 12 | |
| 1 | SIMPLE | s2 | ALL | (null) | (null) | (null) | (null) | 12 | Using where |
Hầu như giống nhau. Cả hai truy vấn đều không sử dụng chỉ mục, tất cả các hàng đều được quét. Bây giờ chúng tôi đang thêm một chỉ mục trên cột rank
.
drop table if exists students;
CREATE TABLE students
(`uid` bigint, `last_name` varchar(5), `first_name` varchar(8), `dob` varchar(10), `email` varchar(16), `rank` int, `grade` int
, key rankkey(rank)
)
;
Giải thích từ truy vấn của bạn:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
-----------------------------------------------------------------------------------------------------------------------------
| 1 | PRIMARY | students | ref | rankkey | rankkey | 5 | const | 1 | Using where |
| 2 | SUBQUERY | (null) | (null) | (null) | (null) | (null) | (null) | (null) | Select tables optimized away |
so với của tôi:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
----------------------------------------------------------------------------------------------------
| 1 | SIMPLE | s1 | ALL | (null) | (null) | (null) | (null) | 12 | |
| 1 | SIMPLE | s2 | ALL | rankkey | (null) | (null) | (null) | 12 | Using where |
Truy vấn của bạn sử dụng chỉ mục, của tôi thì không.
Bây giờ chúng tôi đang thêm một khóa chính vào bảng.
drop table if exists students;
CREATE TABLE students
(`uid` bigint, `last_name` varchar(5), `first_name` varchar(8), `dob` varchar(10), `email` varchar(16), `rank` int, `grade` int
, key rankkey(rank)
, primary key(uid)
);
Giải thích từ truy vấn của bạn:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
-----------------------------------------------------------------------------------------------------------------------------
| 1 | PRIMARY | students | ref | rankkey | rankkey | 5 | const | 1 | Using where |
| 2 | SUBQUERY | (null) | (null) | (null) | (null) | (null) | (null) | (null) | Select tables optimized away |
và từ của tôi:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
-------------------------------------------------------------------------------------------------------------------------------
| 1 | SIMPLE | s1 | ALL | (null) | (null) | (null) | (null) | 12 | |
| 1 | SIMPLE | s2 | index | rankkey | rankkey | 5 | (null) | 12 | Using where; Using index; Not exists |
Bằng cách này, chúng rất có thể nhanh như nhau. Và đây là cách truy vấn và bảng thường được tạo. Mọi bảng phải có khóa chính và nếu bạn đang chạy truy vấn lọc trên cột xếp hạng thường xuyên thì tất nhiên bạn nên có một chỉ mục trên đó. Vì vậy, hầu như không có sự khác biệt. Tất cả bây giờ phụ thuộc vào số hàng bạn có trong bảng của mình, nếu đó là một chỉ mục duy nhất và / hoặc một nhóm. Nhưng điều đó bây giờ sẽ dẫn đến một chút quá xa. Nhưng lưu ý rằng trong ví dụ này có sự khác biệt về số lượng hàng được kiểm tra. Với dữ liệu nhỏ không có sự khác biệt, với khối lượng dữ liệu lớn thì chắc chắn là như vậy. Nhưng (!) Hành vi này có thể thay đổi đối với cả hai truy vấn, tùy thuộc vào chỉ mục.
Điều gì sẽ xảy ra nếu người viết truy vấn mắc lỗi? Điều gì sẽ xảy ra nếu anh ấy viết nó như thế này:
SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.last_name IS NULL;
Truy vấn vẫn hoạt động và hợp lệ, nhưng
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
----------------------------------------------------------------------------------------------------
| 1 | SIMPLE | s1 | ALL | (null) | (null) | (null) | (null) | 12 | |
| 1 | SIMPLE | s2 | ALL | rankkey | (null) | (null) | (null) | 12 | Using where |
một lần nữa chỉ mục không được sử dụng.
Điều gì sẽ xảy ra nếu chúng ta xóa khóa chính một lần nữa và viết truy vấn như sau:
SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.rank IS NULL;
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
-------------------------------------------------------------------------------------------------------------------
| 1 | SIMPLE | s1 | ALL | (null) | (null) | (null) | (null) | 12 | |
| 1 | SIMPLE | s2 | index | rankkey | rankkey | 5 | (null) | 12 | Using where; Using index |
Chỉ mục được sử dụng lại.
Kết luận: Cả hai truy vấn sẽ chạy nhanh như nhau, nếu được thực hiện đúng. Điều tương tự cũng áp dụng cho của tôi nếu được viết có lưu ý đến các chỉ mục.
Hy vọng điều này sẽ hữu ích.