Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jaki jest kanoniczny sposób pobrania rekordu z bazy danych MySQL, który ma najmniejsze/największe pole?

Ten sposób również nie jest niczym niezwykłym:

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

LEFT JOIN działa na podstawie tego, że gdy s1.rank osiąga maksymalną wartość, nie ma s2.rank o większej wartości, a wartości wierszy s2 będą równe NULL.

Ale powiedziałbym, że twój sposób robienia tego jest najczęstszym, najłatwiejszym do zrozumienia sposobem robienia tego, tak.

EDYCJA:Na pytanie, dlaczego czasami jest wolniej:

Wydajność tego zapytania zależy od tego, „jak starannie zostało napisane”. Weź swoje dane jako przykład:

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

Wyjaśnienie zapytania wygląda tak:

| 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 mojego zapytania wygląda tak:

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

Prawie to samo. Żadne z zapytań nie używa indeksu, skanowane są wszystkie wiersze. Teraz dodajemy indeks w kolumnie 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)
    )
;

Wyjaśnienie Twojego zapytania:

| 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 mój:

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

Twoje zapytanie korzysta z indeksu, moje nie.

Teraz dodajemy klucz podstawowy do tabeli.

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

Wyjaśnij w swoim zapytaniu:

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

i z mojego:

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

W ten sposób najprawdopodobniej są równie szybkie. I tak zwykle buduje się zapytanie i tabelę. Każda tabela powinna mieć klucz podstawowy i jeśli bardzo często używasz filtrowania zapytań na kolumnie rangi, powinieneś oczywiście mieć na niej indeks. Więc nie ma prawie żadnej różnicy. Wszystko zależy teraz od tego, ile masz wierszy w swojej tabeli, czy jest to unikalny indeks i/lub klastrowany. Ale to prowadziłoby teraz trochę za daleko. Należy jednak pamiętać, że w tym przykładzie jest różnica w ilości sprawdzanych wierszy. Przy małych ilościach danych nie ma różnicy, przy dużych ilościach danych na pewno. Ale(!) to zachowanie może się zmienić dla obu zapytań, w zależności od indeksu.

Co zrobić, jeśli ten, kto pisze zapytanie, popełni błąd? A jeśli napisze to w ten sposób:

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

Zapytanie nadal działa i jest prawidłowe, 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 |

ponownie indeks nie jest używany.

Co się stanie, jeśli ponownie usuniemy klucz główny i napiszemy zapytanie w ten sposób:

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 |

Indeks jest ponownie używany.

Wniosek: Oba zapytania powinny działać równie szybko, jeśli zostaną wykonane prawidłowo. Twoje jest szybkie, o ile indeks znajduje się w kolumnie rang. To samo dotyczy mojego, jeśli jest pisane z myślą o indeksach.

Mam nadzieję, że to pomoże.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak znaleźć podobne wyniki i posortować według podobieństwa?

  2. Czy mogę SSH do MySQL za pomocą narzędzi GUI?

  3. Jak wyświetlić ostatnie zapytania wykonane na MySQL?

  4. zrobić ID w tabeli mysql auto_increment (po fakcie)

  5. Zezwalaj na wszystkie połączenia zdalne, MySQL