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

Bagaimana cara mengoptimalkan kueri jika tabel berisi 10.000 entri menggunakan MySQL?

Saya akan mencoba menyederhanakan ini SEPENUHNYA dengan meletakkan pemicu di tabel Anda yang lain, dan hanya menambahkan beberapa kolom ke tabel User_Fans Anda... Satu untuk setiap count() masing-masing yang Anda coba dapatkan... dari Posting, PostLikes, PostComments, PostCommentLikes.

Ketika sebuah catatan ditambahkan ke tabel mana pun, cukup perbarui tabel user_fans Anda untuk menambahkan 1 ke hitungan... bagaimanapun, itu akan hampir seketika berdasarkan ID kunci pengguna. Adapun "LIKES"... Serupa, hanya dengan syarat bahwa sesuatu dipicu sebagai "Suka", tambahkan 1.. Kemudian kueri Anda akan menjadi matematika langsung pada catatan tunggal dan tidak bergantung pada APAPUN bergabung untuk menghitung nilai total "tertimbang". Saat tabel Anda semakin besar, kueri juga akan menjadi lebih panjang karena memiliki lebih banyak data untuk dituangkan dan dikumpulkan. Anda akan melalui SETIAP catatan user_fan yang intinya adalah menanyakan setiap catatan dari semua tabel lainnya.

Semua yang dikatakan, menjaga tabel seperti yang Anda miliki, saya akan merestrukturisasi sebagai berikut...

SELECT 
      uf.user_name,
      uf.user_id,
      @pc := coalesce( PostSummary.PostCount, 000000 ) as PostCount,
      @pl := coalesce( PostLikes.LikesCount, 000000 ) as PostLikes,
      @cc := coalesce( CommentSummary.CommentsCount, 000000 ) as PostComments,
      @cl := coalesce( CommentLikes.LikesCount, 000000 ) as CommentLikes,
      @pc + @cc AS sum_post,
      @pl + @cl AS sum_like, 
      @pCalc := (@pc + @cc) * 10 AS post_cal,
      @lCalc := (@pl + @cl) * 5 AS like_cal,
      @pCalc + @lCalc AS `total`
   FROM
      ( select @pc := 0,
               @pl := 0,
               @cc := 0,
               @cl := 0,
               @pCalc := 0
               @lCalc := 0 ) sqlvars,
      user_fans uf
        LEFT JOIN ( select user_id, COUNT(*) as PostCount
                       from post
                       group by user_id ) as PostSummary
           ON uf.user_id = PostSummary.User_ID

        LEFT JOIN ( select user_id, COUNT(*) as LikesCount
                       from post_likes
                       group by user_id ) as PostLikes
           ON uf.user_id = PostLikes.User_ID

        LEFT JOIN ( select user_id, COUNT(*) as CommentsCount
                       from post_comment
                       group by user_id ) as CommentSummary
           ON uf.user_id = CommentSummary.User_ID

        LEFT JOIN ( select user_id, COUNT(*) as LikesCount
                       from post_comment_likes
                       group by user_id ) as CommentLikes
           ON uf.user_id = CommentLikes.User_ID

   ORDER BY 
      `total` DESC 
   LIMIT 20

My variables are abbreviated as 
"@pc" = PostCount
"@pl" = PostLikes
"@cc" = CommentCount
"@cl" = CommentLike
"@pCalc" = weighted calc of post and comment count * 10 weighted value
"@lCalc" = weighted calc of post and comment likes * 5 weighted value

LEFT JOIN to prequeries menjalankan kueri tersebut SEKALI, lalu semuanya digabungkan alih-alih dipukul sebagai sub-kueri untuk setiap catatan. Dengan menggunakan COALESCE(), jika tidak ada entri seperti itu di hasil tabel LEFT JOINed, Anda tidak akan mendapatkan nilai NULL yang mengacaukan perhitungan, jadi saya menetapkannya ke 000000.

KLARIFIKASI PERTANYAAN ANDA

Anda dapat memiliki QUERY sebagai "AS AliasResult". "As" juga dapat digunakan untuk menyederhanakan nama tabel yang panjang agar mudah dibaca. Alias ​​​​juga dapat menggunakan tabel yang sama tetapi sebagai alias berbeda untuk mendapatkan konten serupa, tetapi untuk tujuan yang berbeda.

select
      MyAlias.SomeField
   from
      MySuperLongTableNameInDatabase MyAlias ...

select
      c.LastName,
      o.OrderAmount
   from
      customers c
         join orders o
            on c.customerID = o.customerID  ...

select
      PQ.SomeKey
   from
      ( select ST.SomeKey
           from SomeTable ST
           where ST.SomeDate between X and Y ) as PQ
         JOIN SomeOtherTable SOT
            on PQ.SomeKey = SOT.SomeKey ...

Sekarang, kueri ketiga di atas tidak praktis membutuhkan ( kueri penuh menghasilkan alias "PQ" mewakili "PreQuery" ). Ini dapat dilakukan jika Anda ingin membatasi serangkaian kondisi kompleks lainnya sebelumnya dan menginginkan set yang lebih kecil SEBELUM melakukan penggabungan ekstra ke banyak tabel lain untuk semua hasil akhir.

Karena "FROM" tidak HARUS menjadi tabel yang sebenarnya, tetapi dapat berupa kueri itu sendiri, tempat lain yang digunakan dalam kueri, ia harus tahu cara mereferensikan kumpulan hasil prakueri ini.

Selain itu, saat menanyakan bidang, bidang tersebut juga dapat berupa "Sebagai NamaKolom Akhir" untuk menyederhanakan hasil ke mana pun bidang tersebut akan digunakan.

pilihCONCAT( User.Salutation, User.LastName ) sebagai CourtesyNamefrom ...

pilihOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) sebagai OrderTotalWithTaxfrom ...

Nama kolom "Sebagai" TIDAK diperlukan sebagai agregat, tetapi paling sering terlihat seperti itu.

Sekarang, sehubungan dengan variabel MySQL... Jika Anda melakukan prosedur tersimpan, banyak orang akan mendeklarasikan sebelumnya bahwa mereka menetapkan nilai default sebelum prosedur lainnya. Anda dapat melakukannya sebaris dalam kueri hanya dengan menyetel dan memberikan referensi "Alias" pada hasil tersebut. Saat melakukan variabel ini, pilih akan mensimulasikan selalu mengembalikan nilai SINGLE RECORD senilai. Ini hampir seperti catatan tunggal yang dapat diperbarui yang digunakan dalam kueri. Anda tidak perlu menerapkan kondisi "Gabung" tertentu karena mungkin tidak ada kaitannya dengan tabel lainnya dalam kueri... Intinya, membuat hasil Cartesian, tetapi satu catatan terhadap tabel lain tidak akan pernah dibuat duplikat, jadi tidak ada kerusakan di bagian hilir.

select 
       ...
   from 
      ( select @SomeVar := 0,
               @SomeDate := curdate(),
               @SomeString := "hello" ) as SQLVars

Sekarang, bagaimana sqlvars bekerja. Pikirkan program linier... Satu perintah dieksekusi dalam urutan yang tepat saat kueri berjalan. Nilai itu kemudian disimpan kembali di catatan "SQLVars" yang siap untuk waktu berikutnya. Namun, Anda tidak mereferensikannya sebagai SQLVars.SomeVar atau SQLVars.SomeDate... hanya @SomeVar :=someNewValue. Sekarang, ketika @var digunakan dalam kueri, itu juga disimpan sebagai "Sebagai Nama Kolom" di kumpulan hasil. Kadang-kadang, ini bisa menjadi nilai yang dihitung sebagai placeholder dalam persiapan rekaman berikutnya. Setiap nilai kemudian langsung tersedia untuk baris berikutnya. Jadi, berikan contoh berikut...

select
      @SomeVar := SomeVar * 2 as FirstVal,
      @SomeVar := SomeVar * 2 as SecondVal,
      @SomeVar := SomeVar * 2 as ThirdVal
   from
      ( select @SomeVar := 1 ) sqlvars,
      AnotherTable
   limit 3

Will result in 3 records with the values of 

FirstVal    SecondVal   ThirdVal
2           4           8
16          32          64
128         256         512

Perhatikan bagaimana nilai @SomeVar digunakan saat setiap kolom menggunakannya... Jadi bahkan pada catatan yang sama, nilai yang diperbarui segera tersedia untuk kolom berikutnya... Yang mengatakan, sekarang lihat mencoba membuat jumlah catatan yang disimulasikan / peringkat per setiap pelanggan...

select
      o.CustomerID,
      o.OrderID
      @SeqNo := if( @LastID = o.CustomerID, @SeqNo +1, 1 ) as CustomerSequence,
      @LastID := o.CustomerID as PlaceHolderToSaveForNextRecordCompare
   from
      orders o,
      ( select @SeqNo := 0, @LastID := 0 ) sqlvars
   order by
      o.CustomerID

Klausa "Order By" memaksa hasil dikembalikan secara berurutan terlebih dahulu. Jadi, di sini, catatan per pelanggan dikembalikan. Pertama kali melalui, LastID adalah 0 dan ID pelanggan mengatakan...5. Karena berbeda, ia mengembalikan 1 sebagai @SeqNo, MAKA ia mempertahankan ID pelanggan itu ke dalam bidang @LastID untuk catatan berikutnya. Sekarang, catatan berikutnya untuk pelanggan... ID terakhir adalah sama, jadi dibutuhkan @SeqNo (sekarang =1), dan menambahkan 1 ke 1 dan menjadi #2 untuk pelanggan yang sama... Lanjutkan di jalan.. .

Untuk menjadi lebih baik dalam menulis kueri, lihat tag MySQL dan lihat beberapa kontributor berat. Lihatlah pertanyaan dan beberapa jawaban kompleks dan bagaimana pemecahan masalah bekerja. Bukan untuk mengatakan tidak ada orang lain dengan skor reputasi yang lebih rendah yang baru memulai dan benar-benar kompeten, tetapi Anda akan menemukan siapa yang memberikan jawaban yang baik dan mengapa. Lihat juga riwayat jawaban yang diposting. Semakin banyak Anda membaca dan mengikuti, semakin Anda akan lebih menguasai penulisan kueri yang lebih kompleks.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Grup Karbon Laravel berdasarkan Bulan

  2. Misteri MySQL:Nilai null tidak berbeda dengan string non-null

  3. Mengintegrasikan MySQL dengan Python di Windows

  4. File vs database untuk efisiensi penyimpanan di aplikasi obrolan

  5. Contoh Injeksi PHP/MySQL