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

Mengoptimalkan ORDER BY

Ini adalah pertanyaan yang sangat menarik. Selama pengoptimalannya, Anda mungkin menemukan dan memahami banyak informasi baru tentang cara kerja MySQL. Saya tidak yakin bahwa saya akan punya waktu untuk menulis semuanya secara detail sekaligus, tetapi saya dapat memperbaruinya secara bertahap.

Mengapa lambat

Pada dasarnya ada dua skenario:cepat dan lambat .

Dalam cepat skenario Anda berjalan dalam urutan yang telah ditentukan sebelumnya di atas meja dan mungkin pada saat yang sama dengan cepat mengambil beberapa data dengan id untuk setiap baris dari tabel lain. Dalam hal ini Anda berhenti berjalan segera setelah Anda memiliki cukup baris yang ditentukan oleh klausa LIMIT Anda. Dari mana datangnya pesanan? Dari indeks b-tree yang Anda miliki di tabel atau urutan hasil yang ditetapkan dalam subquery.

Dalam lambat skenario Anda tidak memiliki urutan yang telah ditentukan sebelumnya, dan MySQL harus secara implisit memasukkan semua data ke dalam tabel sementara, mengurutkan tabel pada beberapa bidang dan mengembalikan n baris dari klausa LIMIT Anda. Jika salah satu bidang yang Anda masukkan ke dalam tabel sementara itu bertipe TEXT (bukan VARCHAR), MySQL bahkan tidak mencoba untuk menyimpan tabel itu di RAM dan mem-flush dan mengurutkannya pada disk (karenanya pemrosesan IO tambahan).

Hal pertama yang harus diperbaiki

Ada banyak situasi ketika Anda tidak dapat membuat indeks yang memungkinkan Anda untuk mengikuti urutannya (ketika Anda ORDER BY kolom dari tabel yang berbeda, misalnya), jadi aturan praktis dalam situasi seperti itu adalah meminimalkan data yang akan dimasukkan MySQL dalam tabel sementara. Bagaimana kamu melakukannya? Anda hanya memilih pengidentifikasi baris dalam subkueri dan setelah Anda memiliki id, Anda menggabungkan id ke tabel itu sendiri dan tabel lain untuk mengambil konten. Yaitu Anda membuat meja kecil dengan pesanan dan kemudian menggunakan skenario cepat. (Ini sedikit bertentangan dengan SQL pada umumnya, tetapi setiap rasa SQL memiliki caranya sendiri untuk mengoptimalkan kueri seperti itu).

Secara kebetulan, SELECT -- everything is ok here terlihat lucu, karena ini adalah tempat pertama yang tidak baik.

SELECT p.*
    , u.name user_name, u.status user_status
    , c.name city_name, t.name town_name, d.name dist_name
    , pm.meta_name, pm.meta_email, pm.meta_phone
    , (SELECT concat("{", 
        '"id":"', pc.id, '",', 
        '"content":"', replace(pc.content, '"', '\\"'), '",', 
        '"date":"', pc.date, '",', 
        '"user_id":"', pcu.id, '",', 
        '"user_name":"', pcu.name, '"}"') last_comment_json 
        FROM post_comments pc 
        LEFT JOIN users pcu ON (pcu.id = pc.user_id) 
        WHERE pc.post_id = p.id
        ORDER BY pc.id DESC LIMIT 1) AS last_comment
FROM (
    SELECT id
    FROM posts p
    WHERE p.status = 'published'
    ORDER BY 
        (CASE WHEN p.created_at >= unix_timestamp(now() - INTERVAL p.reputation DAY) 
            THEN +p.reputation ELSE NULL END) DESC, 
        p.id DESC
    LIMIT 0,10
) ids
JOIN posts p ON ids.id = p.id  -- mind the join for the p data
LEFT JOIN users u ON (u.id = p.user_id)
LEFT JOIN citys c ON (c.id = p.city_id)
LEFT JOIN towns t ON (t.id = p.town_id)
LEFT JOIN dists d ON (d.id = p.dist_id)
LEFT JOIN post_metas pm ON (pm.post_id = p.id)
;

Itu adalah langkah pertama, tetapi bahkan sekarang Anda dapat melihat bahwa Anda tidak perlu membuat serialisasi LEFT JOINS dan json yang tidak berguna ini untuk baris yang tidak Anda perlukan. (Saya melewatkan GROUP BY p.id , karena saya tidak melihat LEFT JOIN mana yang mungkin menghasilkan beberapa baris, Anda tidak melakukan agregasi apa pun).

belum menulis tentang:

  • indeks
  • memformulasi ulang klausa CASE (gunakan UNION ALL)
  • mungkin memaksa indeks


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tidak dapat mengambil id baris menggunakan pdo

  2. Tampilkan Tabel di Database SQLite dengan Python

  3. MySQL Case Insensitive tapi Accent Sensitive UTF8 Unique Key

  4. Java - Pengecualian di utas utama java.lang.Error:Masalah kompilasi yang belum terselesaikan

  5. Mengapa MySQL mengizinkan grup berdasarkan kueri TANPA fungsi agregat?