sql >> Databáze >  >> RDS >> Mysql

Jaký je kanonický způsob, jak stáhnout záznam z databáze MySQL, který má nejmenší/největší pole?

Tento způsob také není neobvyklý:

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

LEFT JOIN funguje na základě toho, že když je s1.rank na své maximální hodnotě, neexistuje s2.rank s vyšší hodnotou a hodnoty s2 rows budou NULL.

Ale řekl bych, že váš způsob, jak to udělat, je nejběžnější, nejsnáze pochopitelný způsob, jak to udělat, ano.

EDIT:K otázce, proč je to někdy pomalejší:

Výkon tohoto dotazu závisí na tom, „jak pečlivě je napsán“. Vezměte si svá data jako příklad:

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

Vysvětlení vašeho dotazu vypadá takto:

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

Ten z mého dotazu takto:

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

Skoro stejné. Ani jeden dotaz nepoužívá index, jsou skenovány všechny řádky. Nyní přidáváme index do sloupce 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)
    )
;

Vysvětlení z vašeho dotazu:

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

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

Váš dotaz používá index, můj nikoli.

Nyní do tabulky přidáváme primární klíč.

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

Vysvětlete z vašeho dotazu:

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

a od mého:

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

Tímto způsobem jsou s největší pravděpodobností stejně rychlé. A takto je obvykle postaven dotaz a tabulka. Každá tabulka by měla mít primární klíč a pokud velmi často spouštíte filtrování dotazů ve sloupci pořadí, měli byste na něm mít samozřejmě index. Takže v tom není skoro žádný rozdíl. Vše nyní závisí na tom, kolik řádků máte v tabulce, zda se jedná o jedinečný index a/nebo seskupený index. Ale to by teď zavedlo příliš daleko. Všimněte si však, že v tomto příkladu je rozdíl v tom, kolik řádků se zkoumá. U malých dat žádný rozdíl, u velkých objemů dat určitě ano. Ale(!) toto chování se může změnit pro oba dotazy v závislosti na indexu.

Co když ten, kdo dotaz píše, udělá chybu? Co když to napíše takto:

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

Dotaz stále funguje a je platný, ale

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

index se opět nepoužívá.

Co když primární klíč opět odstraníme a dotaz napíšeme takto:

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 |

Opět je použit index.

Závěr: Oba dotazy by měly běžet stejně rychle, pokud jsou provedeny správně. Váš je rychlý, pokud je index ve sloupci pořadí. Totéž platí pro můj, pokud je napsán s ohledem na indexy.

Doufám, že to pomůže.




  1. Vytváření dočasných tabulek v MySQL Stored Procedure

  2. Vytvoření kopie databáze v PostgreSQL

  3. Proč postgres v mém dotazu nepoužívá index

  4. Použití oprávnění sloupců pro tabulku přes spouštěč