Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Apa cara kanonik untuk menarik catatan dari database MySQL yang memiliki bidang terkecil/terbesar?

Cara ini juga tidak jarang:

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

LEFT JOIN bekerja atas dasar bahwa ketika s1.rank berada pada nilai maksimumnya, tidak ada s2.rank dengan nilai yang lebih besar dan nilai baris s2 akan menjadi NULL.

Tapi menurut saya cara Anda melakukannya adalah cara yang paling umum dan paling mudah dipahami, ya.

EDIT:Pada pertanyaan mengapa terkadang lebih lambat:

Kinerja kueri ini tergantung pada "seberapa hati-hati penulisannya". Ambil data Anda sebagai contoh:

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

Penjelasan kueri Anda terlihat seperti ini:

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

Yang dari kueri saya seperti ini:

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

Hampir sama. Tidak ada kueri yang menggunakan indeks, semua baris dipindai. Sekarang kita menambahkan indeks pada 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)
    )
;

Penjelasan dari kueri Anda:

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

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

Permintaan Anda menggunakan indeks, milik saya tidak.

Sekarang kita menambahkan kunci utama ke 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)
    );

Jelaskan dari pertanyaan Anda:

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

dan dari saya:

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

Dengan cara ini mereka kemungkinan besar sama cepatnya. Dan beginilah cara kueri dan tabel biasanya dibuat. Setiap tabel harus memiliki kunci utama dan jika Anda sering menjalankan pemfilteran kueri pada kolom peringkat, tentu saja Anda harus memiliki indeks di dalamnya. Jadi hampir tidak ada perbedaan. Semuanya sekarang tergantung pada berapa banyak baris yang Anda miliki di tabel Anda, apakah itu indeks unik dan/atau indeks berkerumun. Tapi itu akan membawa sekarang agak terlalu jauh. Namun perhatikan, bahwa dalam contoh ini ada perbedaan dalam jumlah baris yang diperiksa. Dengan data kecil tidak ada perbedaan, dengan volume data yang besar pasti ada. Tapi(!) perilaku ini mungkin berubah untuk kedua kueri, bergantung pada indeks.

Bagaimana jika orang yang menulis kueri melakukan kesalahan? Bagaimana jika dia menulis seperti ini:

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

Kueri masih berfungsi dan valid, tetapi

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

lagi indeks tidak digunakan.

Bagaimana jika kita menghapus kunci utama lagi dan menulis kueri seperti ini:

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 digunakan lagi.

Kesimpulan: Kedua kueri harus berjalan sama cepatnya, jika dilakukan dengan benar. Permintaan Anda cepat selama indeks berada di kolom peringkat. Hal yang sama berlaku untuk saya jika ditulis dengan mempertimbangkan indeks.

Semoga membantu.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL – Penjelasan Pengkodean dan Pengumpulan Karakter Basis Data

  2. host 'localhost' tidak diizinkan untuk terhubung ke server MySQL ini (#1130)

  3. cari beberapa kata kunci dengan php dan mysql (di mana X suka)

  4. Cara menghitung peringkat di MySQL

  5. Bekerja dengan Database MySQL cPanel