Det här sättet är inte heller ovanligt:
SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.uid IS NULL;
LEFT JOIN fungerar utifrån att när s1.rank har sitt maximala värde, finns det ingen s2.rank med ett högre värde och s2 radernas värden kommer att vara NULL.
Men jag skulle säga att ditt sätt att göra det på är det vanligaste, lättaste att förstå sättet att göra det på, ja.
EDIT:På frågan varför det är långsammare ibland:
Prestandan för den här frågan beror på "hur noggrant den är skriven". Ta din data som exempel:
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)
;
Förklaringen till din fråga ser ut så här:
| 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 | |
Den från min fråga så här:
| 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 |
Nästan samma. Ingen av sökfrågorna använder ett index, alla rader skannas. Nu lägger vi till ett index på kolumnen 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)
)
;
Förklaringen från din fråga:
| 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 |
kontra mitt:
| 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 |
Din fråga använder indexet, min gör det inte.
Nu lägger vi till en primärnyckel i tabellen.
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)
);
Förklara från din fråga:
| 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 |
och från min:
| 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 |
På så sätt är de med största sannolikhet lika snabba. Och det är så frågan och tabellen vanligtvis är uppbyggd. Varje tabell bör ha en primärnyckel och om du kör en frågefiltrering på rankkolumnen mycket ofta bör du naturligtvis ha ett index på den. Så det är nästan ingen skillnad. Allt beror nu på hur många rader du har i din tabell, om det är ett unikt index och/eller ett kluster. Men det skulle leda lite för långt nu. Men observera att i det här exemplet är det skillnad på hur mycket rader som undersöks. Med små data är det ingen skillnad, med stora datavolymer är det säkert. Men(!) detta beteende kan ändras för båda frågorna, beroende på index.
Vad händer om den som skriver frågan gör ett misstag? Tänk om han skriver det så här:
SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.last_name IS NULL;
Frågan fungerar fortfarande och är giltig, men
| 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 |
återigen används inte indexet.
Vad händer om vi tar bort primärnyckeln igen och skriver frågan så här:
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 |
Index används igen.
Slutsats: Båda frågorna bör köras lika snabbt om de görs rätt. Dina är snabba så länge som ett index är i rangkolumnen. Detsamma gäller för min om den är skriven med index i åtanke.
Hoppas detta hjälper.