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

Mengapa kondisi IN lebih lambat dari =di sql?

Ringkasan:Ini adalah masalah yang diketahui di MySQL dan diperbaiki di MySQL 5.6.x. Masalahnya adalah karena optimasi yang hilang ketika subquery yang menggunakan IN salah diidentifikasi sebagai subquery dependen, bukan subquery independen.

Saat Anda menjalankan EXPLAIN pada kueri asli, ia mengembalikan ini:

1  'PRIMARY'             'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
2  'DEPENDENT SUBQUERY'  'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
3  'DEPENDENT SUBQUERY'  'question_law'          'ALL'  ''  ''  ''  ''  10040  'Using where'

Saat Anda mengubah IN ke = Anda mendapatkan ini:

1  'PRIMARY'   'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
2  'SUBQUERY'  'question_law_version'  'ALL'  ''  ''  ''  ''  10148  'Using where'
3  'SUBQUERY'  'question_law'          'ALL'  ''  ''  ''  ''  10040  'Using where'

Setiap subkueri dependen dijalankan satu kali per baris dalam kueri yang memuatnya, sedangkan subkueri dijalankan hanya sekali. MySQL terkadang dapat mengoptimalkan subquery dependen ketika ada kondisi yang dapat dikonversi menjadi gabungan tetapi di sini tidak demikian.

Sekarang ini tentu saja meninggalkan pertanyaan mengapa MySQL percaya bahwa versi IN perlu menjadi subquery yang bergantung. Saya telah membuat versi kueri yang disederhanakan untuk membantu menyelidiki ini. Saya membuat dua tabel 'foo' dan 'bar' di mana yang pertama hanya berisi kolom id, dan yang terakhir berisi id dan foo id (meskipun saya tidak membuat batasan kunci asing). Kemudian saya mengisi kedua tabel dengan 1000 baris:

CREATE TABLE foo (id INT PRIMARY KEY NOT NULL);
CREATE TABLE bar (id INT PRIMARY KEY, foo_id INT NOT NULL);

-- populate tables with 1000 rows in each

SELECT id
FROM foo
WHERE id IN
(
    SELECT MAX(foo_id)
    FROM bar
);

Kueri yang disederhanakan ini memiliki masalah yang sama seperti sebelumnya - pemilihan dalam diperlakukan sebagai subkueri dependen dan tidak ada pengoptimalan yang dilakukan, menyebabkan kueri dalam dijalankan sekali per baris. Kueri membutuhkan waktu hampir satu detik untuk dijalankan. Mengubah IN ke = lagi memungkinkan kueri berjalan hampir seketika.

Kode yang saya gunakan untuk mengisi tabel ada di bawah, jika ada yang ingin mereproduksi hasilnya.

CREATE TABLE filler (
        id INT NOT NULL PRIMARY KEY AUTO_INCREMENT
) ENGINE=Memory;

DELIMITER $$

CREATE PROCEDURE prc_filler(cnt INT)
BEGIN
        DECLARE _cnt INT;
        SET _cnt = 1;
        WHILE _cnt <= cnt DO
                INSERT
                INTO    filler
                SELECT  _cnt;
                SET _cnt = _cnt + 1;
        END WHILE;
END
$$

DELIMITER ;

CALL prc_filler(1000);

INSERT foo SELECT id FROM filler;
INSERT bar SELECT id, id FROM filler;


  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_num_rows() mengharapkan parameter 1 menjadi sumber daya, boolean diberikan dalam

  2. MySQL ERROR 1290 (HY000) --secure-file-priv option

  3. Bagaimana cara mengisi tanggal yang hilang di MySQL?

  4. Cara Mendapatkan Catatan 15 Hari Terakhir di MySQL

  5. Apa operator <=> ini di MySQL?