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

kueri mahal menurunkan server basis data -- mencari cara untuk menguranginya

Hmm, saya mungkin mencoba menulis kueri Anda seperti ini:

SELECT Sale_Item.deleted, Sale_Item.deleted_by,
       Sale_Item.sale_time, Sale_Item.sale_date,
       Sale_Item.comment,
       Sale_Item.payment_type,
       Sale_Item.customer_id,
       Sale_Item.employee_id,
       Sale_Item.category,
       Sale_Item.sale_id, Sale_Item.item_id, NULL as item_kit_id, Sale_Item.line, 
       Sale_Item.supplier_id,
       Sale_Item.serialnumber, Sale_Item.description,
       Sale_Item.quantity_purchased, Sale_Item.item_cost_price, Sale_Item.item_unit_price,
       Sale_Item.discount_percent,
       Sale_Item.lineSubtotal,
       Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + Sale_Item.non_cumulative) * COALESCE(Tax.cumulative, 0) AS lineTax,
       Sale_Item.lineSubtotal + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + Sale_Item.non_cumulative) * COALESCE(Tax.cumulative, 0)) AS lineTotal,
       Sale_Item.lineSubtotal - (Sale_Item.item_cost_price * Sale_Item.quantity_purchased) AS profit

FROM (SELECT Sale.deleted, Sale.deleted_by,
             Sale.sale_time, DATE(Sale.sale_time) AS sale_date,
             Sale.comment,
             Sale.payment_type,
             Sale.customer_id,
             Sale.employee_id,
             Item.category,
             Sale_Item.sale_id, Sale_Item.item_id, NULL as item_kit_id, Sale_Item.line, 
             Sale_Item.supplier_id,
             Sale_Item.serialnumber, Sale_Item.description,
             Sale_Item.quantity_purchased, Sale_Item.item_cost_price, Sale_Item.item_unit_price,
             Sale_Item.discount_percent,
             (Sale_Item.item_unit_price * Sale_Item.quantity_purchased) - (Sale_Item.item_unit_price * Sale_Item.quantity_purchased * Sale_Item.discount_percent / 100) as lineSubtotal                 
      FROM phppos_sales_items Sale_Item
      JOIN phppos_sales Sale
        ON Sale.sale_id = Sale_Item.sale_id
           AND Sale.sale_time >= TIMESTAMP('2014-04-01')
           AND Sale.sale_time < TIMESTAMPADD(MONTH, 1, '2014-04-01')
           AND Sale.location_id = 1
           AND Sale.store_account_payment = 0) Sale_Item

LEFT JOIN (SELECT Tax.sale_id, Tax.item_id, Tax.line,
                  SUM(CASE WHEN Tax.cumulative = 1 THEN Tax.percent ELSE 0 END) as cumulative,
                  SUM(CASE WHEN Tax.cumulative <> 1 THEN Tax.percent ELSE 0 END) as non_cumulative
           FROM phppos_sales_item_taxes Tax
           JOIN phppos_sales Sale
             ON Sale.sale_id = Tax.sale_id
                AND Sale.sale_time >= TIMESTAMP('2014-04-01')
                AND Sale.sale_time < TIMESTAMPADD(MONTH, 1, '2014-04-01')
                AND Sale.location_id = 1
                AND Sale.store_account_payment = 0
           GROUP BY Tax.sale_id, Tax.item_id, Tax.line) Tax
       ON Tax.sale_id = Sale_Item.sale_id
          AND Tax.item_id = Sale_Item.sale_id
          AND Tax.line =Sale_Item.line 

Memindahkan beberapa kolom untuk tujuan organisasi. Ini seharusnya tidak berpengaruh besar pada waktu pemrosesan.

Saya menghapus referensi ke phppos_suppliers sebagai:

  1. Anda tidak menggunakan kolom apa pun dari tabel
  2. Ini adalah LEFT JOIN , artinya Anda tidak memerlukan baris untuk ada di sana.

Saya memindahkan GROUP BY menjadi subquery baru, karena phppos_sales_item_taxes adalah satu-satunya tabel yang dapat memiliki baris duplikat untuk kriteria yang diberikan. Saya menyertakan referensi ke phppos_sales karena saya tidak yakin apakah pengoptimal MySQL (atau apa pun, sungguh) cukup pintar untuk menekan citeria ke bawah.

Bagian utama kueri telah dipindahkan ke subkueri agar saya tidak perlu mengetikkan rumus untuk lineSubtotal beberapa kali. Saya telah menggunakan rumus yang sama, tetapi ada versi yang disederhanakan yang tersedia:

Sale_Item.item_unit_price * Sale_Item.quantity_purchased * (1 - (Sale_Item.discount_percent / 100)) as lineSubtotal  

Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative + Tax.cumulative + Tax.non_cumulative * Tax.cumulative, 0) as Tax

.... Anda mungkin harus menjalankan ini dengan akuntansi, karena mereka cenderung (dapat dimengerti) sensitif tentang urutan operasi. Ini mungkin menghasilkan runtime yang lebih cepat tetapi saya meragukannya; kebanyakan ini tentang penyederhanaan istilah menjadi sesuatu yang lebih mudah dibaca.

Anda tidak memberikan tata letak tabel apa pun untuk separuh kueri lainnya, tetapi saya menganggapnya serupa. Modifikasi terkait diserahkan sebagai latihan untuk pembaca.

Strategi Mitigasi Umum

Di luar kemungkinan percepatan perubahan kueri, ada beberapa hal yang dapat Anda lakukan untuk mengurangi masalah:

  1. Di lapisan aplikasi Anda, paksa kueri ini (dan mungkin yang lain) untuk melalui proses pengiriman pekerjaan yang hasilnya dapat diambil nanti. Salinan baru kueri ini tidak dapat dijalankan hingga salinan sebelumnya selesai. Saya berasumsi php memiliki perpustakaan yang ada untuk ini. Cukup membatasi pengiriman secara umum mungkin yang Anda butuhkan.
  2. Data yang diambil tampaknya dapat di-cache - simpan semuanya sebelum sale_date yang terakhir diproses , dan kemudian hanya mendapatkan informasi baru saat itu juga (walaupun transformasinya tidak terlalu berbeda dari aslinya - namun, tidak melakukan lebih banyak bergabung dapat membantu).
  3. Larang kueri selama rentang waktu pemrosesan saat ini. Ini akan menjaga sistem agar tidak mencoba mengakses baris yang belum di-commit, dan berpotensi menjauh dari halaman indeks yang sedang dimodifikasi. Trik semacam ini berfungsi paling baik jika penyimpanan Anda ditata untuk memanfaatkan I/O bersamaan.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ambil data untuk beberapa single atau referensi tanpa operator sejenis

  2. Laravel - Querybuilder dengan join dan concat

  3. MySQL mendapatkan nilai non null pertama setelah grup oleh

  4. Bagaimana cara mengakses mysql di luar cluster kubernetes saya?

  5. Salin dua kolom dari satu tabel ke tabel lainnya, tetapi hanya nilai unik