sql >> Database >  >> RDS >> Mysql

Wat is de canonieke manier om een ​​record uit een MySQL-database te halen met een minst/grootst veld?

Deze manier is ook niet ongebruikelijk:

SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.uid IS NULL;

De LEFT JOIN werkt op basis van het feit dat wanneer s1.rank de maximale waarde heeft, er geen s2.rank is met een hogere waarde en dat de waarden van de s2 rijen NULL zijn.

Maar ik zou zeggen dat jouw manier om het te doen de meest gebruikelijke, gemakkelijkst te begrijpen manier is om het te doen, ja.

EDIT:Op de vraag waarom het soms langzamer is:

De prestatie van deze query hangt af van "hoe zorgvuldig deze is geschreven". Uw gegevens als voorbeeld genomen:

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)
;

De uitleg van uw vraag ziet er als volgt uit:

| 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 |             |

Die van mijn vraag als volgt:

| 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 |

Bijna hetzelfde. Geen van beide query's gebruikt een index, alle rijen worden gescand. Nu voegen we een index toe aan kolom 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)
    )
;

De uitleg van uw vraag:

| 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 |

versus de mijne:

| 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 |

Uw zoekopdracht gebruikt de index, de mijne niet.

Nu voegen we een primaire sleutel toe aan de tabel.

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)
    );

Leg uit uw vraag:

| 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 |

en van de mijne:

| 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 |

Op deze manier zijn ze waarschijnlijk even snel. En dit is hoe de query en de tabel meestal worden opgebouwd. Elke tabel zou een primaire sleutel moeten hebben en als u heel vaak een queryfilter op de rangkolom uitvoert, moet u er natuurlijk een index op hebben. Er is dus bijna geen verschil. Het hangt nu allemaal af van hoeveel rijen je in je tabel hebt, of het een unieke index en/of een geclusterde index is. Maar dat zou nu een beetje te ver leiden. Maar merk op dat er in dit voorbeeld een verschil is in het aantal rijen dat wordt onderzocht. Met kleine data is er geen verschil, met grote datavolumes wel. Maar(!) kan dit gedrag voor beide zoekopdrachten veranderen, afhankelijk van de index.

Wat als degene die de query schrijft een fout maakt? Wat als hij het zo schrijft:

SELECT s1.*
FROM students s1
LEFT JOIN students s2 ON s1.rank < s2.rank
WHERE s2.last_name IS NULL;

De query werkt nog steeds en is geldig, maar

| 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 |

opnieuw wordt de index niet gebruikt.

Wat als we de primaire sleutel weer verwijderen en de query als volgt schrijven:

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 wordt opnieuw gebruikt.

Conclusie: Beide zoekopdrachten zouden even snel moeten lopen, als ze goed worden uitgevoerd. De jouwe is snel zolang een index in de rangordekolom staat. Hetzelfde geldt voor de mijne, indien geschreven met indexen in gedachten.

Ik hoop dat dit helpt.




  1. MySQL-verbindingen van localhost beperken om de beveiliging te verbeteren

  2. IllegalArgumentException:Type kan niet null zijn

  3. Kan de waarde die ik wilde selecteren niet ophalen met behulp van Opgeslagen procedure

  4. postgreSQL - in vs any