Skenario singkatnya: Sebuah tabel dengan lebih dari 16 juta catatan [ukuran 2GB]. Semakin tinggi LIMIT diimbangi dengan SELECT, semakin lambat kueri menjadi, saat menggunakan ORDER OLEH * primary_key *
Begitu
SELECT * FROM large ORDER BY `id` LIMIT 0, 30
membutuhkan waktu jauh lebih sedikit daripada
SELECT * FROM large ORDER BY `id` LIMIT 10000, 30
Itu hanya memesan 30 catatan dan bagaimanapun juga. Jadi bukan overhead dari ORDER BY.
Sekarang ketika mengambil 30 baris terbaru dibutuhkan sekitar 180 detik. Bagaimana saya bisa mengoptimalkan permintaan sederhana itu?
mysql
performance
sql-order-by
limit
Rahman
sumber
sumber
Jawaban:
Itu normal bahwa offset yang lebih tinggi memperlambat permintaan, karena permintaan harus menghitung
OFFSET + LIMIT
catatan pertama (dan hanya mengambilLIMIT
dari mereka). Semakin tinggi nilai ini, semakin lama kueri berjalan.Kueri tidak dapat langsung ke
OFFSET
karena, pertama, catatan bisa memiliki panjang yang berbeda, dan, kedua, bisa ada kesenjangan dari catatan yang dihapus. Perlu memeriksa dan menghitung setiap catatan pada jalannya.Dengan asumsi bahwa
id
adalahPRIMARY KEY
dariMyISAM
meja, Anda dapat mempercepat itu dengan menggunakan trik ini:Lihat artikel ini:
sumber
ORDER BY
atau indeks mencakup semua bidang yang Anda butuhkan, Anda tidak perlu solusi ini.postgresql
. Ini adalah jawaban khusus MySQL.Saya sendiri memiliki masalah yang sama persis. Mengingat fakta bahwa Anda ingin mengumpulkan sejumlah besar data ini dan bukan set khusus 30 Anda mungkin akan menjalankan loop dan menambah offset dengan 30.
Jadi yang bisa Anda lakukan adalah:
WHERE id > lastId limit 0,30
Jadi, Anda selalu dapat memiliki NOL offset. Anda akan kagum dengan peningkatan kinerja.
sumber
MySQL tidak dapat langsung menuju ke catatan 10.000 (atau byte 80000 sebagai saran Anda) karena ia tidak dapat menganggap bahwa itu dikemas / dipesan seperti itu (atau bahwa ia memiliki nilai kontinu dalam 1 hingga 10.000). Meskipun mungkin seperti itu dalam kenyataannya, MySQL tidak dapat berasumsi bahwa tidak ada lubang / kesenjangan / id yang dihapus.
Jadi, seperti yang dicatat bobs, MySQL harus mengambil 10.000 baris (atau melintasi hingga 10.000 entri indeks aktif
id
) sebelum menemukan 30 untuk kembali.EDIT : Untuk mengilustrasikan poin saya
Perhatikan bahwa meskipun
akan lambat (er) ,
akan cepat (er) , dan akan mengembalikan hasil yang sama asalkan tidak ada yang hilang
id
(yaitu kesenjangan).sumber
Saya menemukan contoh menarik untuk mengoptimalkan permintaan SELECT ORDER BY id LIMIT X, Y. Saya memiliki 35 juta baris sehingga butuh 2 menit untuk menemukan berbagai baris.
Ini triknya:
Cukup masukkan WHERE dengan id terakhir yang Anda peroleh meningkatkan kinerja. Bagi saya itu dari 2 menit hingga 1 detik :)
Trik menarik lainnya di sini: http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/
Ini juga berfungsi dengan string
sumber
Bagian yang menyita waktu dari dua kueri mengambil baris dari tabel. Secara logis, dalam
LIMIT 0, 30
versi ini, hanya 30 baris yang perlu diambil. DalamLIMIT 10000, 30
versi ini, 10.000 baris dievaluasi dan 30 baris dikembalikan. Mungkin ada beberapa optimasi yang dapat saya lakukan dalam proses membaca data, tetapi pertimbangkan hal berikut:Bagaimana jika Anda memiliki klausa WHERE dalam kueri? Mesin harus mengembalikan semua baris yang memenuhi syarat, lalu mengurutkan data, dan akhirnya mendapatkan 30 baris.
Juga pertimbangkan kasus di mana baris tidak diproses dalam urutan ORDER BY. Semua baris yang memenuhi syarat harus disortir untuk menentukan baris mana yang akan dikembalikan.
sumber
Bagi mereka yang tertarik dengan perbandingan dan angka :)
Eksperimen 1: Dataset berisi sekitar 100 juta baris. Setiap baris berisi beberapa BIGINT, TINYINT, serta dua bidang TEKS (sengaja) yang berisi sekitar 1 rb karakter.
SELECT * FROM post ORDER BY id LIMIT {offset}, 5
SELECT t.* FROM (SELECT id FROM post ORDER BY id LIMIT {offset}, 5) AS q JOIN post t ON t.id = q.id
... WHERE id>xxx LIMIT 0,5
,, tidak muncul di sini karena itu harus waktu yang konstan.Eksperimen 2: Hal serupa, kecuali bahwa satu baris hanya memiliki 3 BIGINT.
sumber