Ini permintaan lambat saya:
SELECT `products_counts`.`cid`
FROM
`products_counts` `products_counts`
LEFT OUTER JOIN `products` `products` ON (
`products_counts`.`product_id` = `products`.`id`
)
LEFT OUTER JOIN `trademarks` `trademark` ON (
`products`.`trademark_id` = `trademark`.`id`
)
LEFT OUTER JOIN `suppliers` `supplier` ON (
`products_counts`.`supplier_id` = `supplier`.`id`
)
WHERE
`products_counts`.product_id IN
(159, 572, 1075, 1102, 1145, 1162, 1660, 2355, 2356, 2357, 3236, 6471, 6472, 6473, 8779, 9043, 9095, 9336, 9337, 9338, 9445, 10198, 10966, 10967, 10974, 11124, 11168, 16387, 16689, 16827, 17689, 17920, 17938, 17946, 17957, 21341, 21352, 21420, 21421, 21429, 21544, 27944, 27988, 30194, 30196, 30230, 30278, 30699, 31306, 31340, 32625, 34021, 34047, 38043, 43743, 48639, 48720, 52453, 55667, 56847, 57478, 58034, 61477, 62301, 65983, 66013, 66181, 66197, 66204, 66407, 66844, 66879, 67308, 68637, 73944, 74037, 74060, 77502, 90963, 101630, 101900, 101977, 101985, 101987, 105906, 108112, 123839, 126316, 135156, 135184, 138903, 142755, 143046, 143193, 143247, 144054, 150164, 150406, 154001, 154546, 157998, 159896, 161695, 163367, 170173, 172257, 172732, 173581, 174001, 175126, 181900, 182168, 182342, 182858, 182976, 183706, 183902, 183936, 184939, 185744, 287831, 362832, 363923, 7083107, 7173092, 7342593, 7342594, 7342595, 7728766)
ORDER BY
products_counts.inflow ASC,
supplier.delivery_period ASC,
trademark.sort DESC,
trademark.name ASC
LIMIT
0, 3;
Waktu permintaan rata-rata adalah 4,5 detik pada dataset saya dan ini tidak dapat diterima.
Solusi yang saya lihat:
Tambahkan semua kolom dari klausa pesanan ke products_counts
tabel. Tapi saya punya ~ 10 jenis pesanan dalam aplikasi, jadi saya harus membuat banyak kolom dan indeks. Plus products_counts
memiliki pembaruan / sisipan / penghapusan yang sangat intensif, jadi saya harus segera memperbarui semua kolom terkait pesanan (menggunakan pemicu?).
Apakah ada solusi lain?
Menjelaskan:
+----+-------------+-----------------+--------+---------------------------------------------+------------------------+---------+----------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+--------+---------------------------------------------+------------------------+---------+----------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | products_counts | range | product_id_supplier_id,product_id,pid_count | product_id_supplier_id | 4 | NULL | 227 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | products | eq_ref | PRIMARY | PRIMARY | 4 | uaot.products_counts.product_id | 1 | |
| 1 | SIMPLE | trademark | eq_ref | PRIMARY | PRIMARY | 4 | uaot.products.trademark_id | 1 | |
| 1 | SIMPLE | supplier | eq_ref | PRIMARY | PRIMARY | 4 | uaot.products_counts.supplier_id | 1 | |
+----+-------------+-----------------+--------+---------------------------------------------+------------------------+---------+----------------------------------+------+----------------------------------------------+
Struktur tabel:
CREATE TABLE `products_counts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) unsigned NOT NULL,
`supplier_id` int(11) unsigned NOT NULL,
`count` int(11) unsigned NOT NULL,
`cid` varchar(64) NOT NULL,
`inflow` varchar(10) NOT NULL,
`for_delete` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `cid` (`cid`),
UNIQUE KEY `product_id_supplier_id` (`product_id`,`supplier_id`),
KEY `product_id` (`product_id`),
KEY `count` (`count`),
KEY `pid_count` (`product_id`,`count`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`external_id` varchar(36) NOT NULL,
`name` varchar(255) NOT NULL,
`category_id` int(11) unsigned NOT NULL,
`trademark_id` int(11) unsigned NOT NULL,
`photo` varchar(255) NOT NULL,
`sort` int(11) unsigned NOT NULL,
`otech` tinyint(1) unsigned NOT NULL,
`not_liquid` tinyint(1) unsigned NOT NULL DEFAULT '0',
`applicable` varchar(255) NOT NULL,
`code_main` varchar(64) NOT NULL,
`code_searchable` varchar(128) NOT NULL,
`total` int(11) unsigned NOT NULL,
`slider` int(11) unsigned NOT NULL,
`slider_title` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `external_id` (`external_id`),
KEY `category_id` (`category_id`),
KEY `trademark_id` (`trademark_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `trademarks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`external_id` varchar(36) NOT NULL,
`name` varchar(255) NOT NULL,
`country_id` int(11) NOT NULL,
`sort` int(11) unsigned NOT NULL DEFAULT '0',
`sort_list` int(10) unsigned NOT NULL DEFAULT '0',
`is_featured` tinyint(1) unsigned NOT NULL,
`is_direct` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `external_id` (`external_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `suppliers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`external_id` varchar(36) NOT NULL,
`code` varchar(64) NOT NULL,
`name` varchar(255) NOT NULL,
`delivery_period` tinyint(1) unsigned NOT NULL,
`is_default` tinyint(1) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `external_id` (`external_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Informasi server MySQL:
mysqld Ver 5.5.45-1+deb.sury.org~trusty+1 for debian-linux-gnu on i686 ((Ubuntu))
(inflow, product_id)
?innodb_buffer_pool_size
. Biasanya sekitar 70% dari RAM yang tersedia bagus.Jawaban:
Meninjau definisi tabel Anda menunjukkan bahwa Anda memiliki indeks yang cocok di seluruh tabel yang terlibat. Ini harus menyebabkan sambungan terjadi secepat mungkin dalam batas
MySQL's
logika bergabung.Namun, pengurutan dari beberapa tabel lebih kompleks.
Pada 2007, Sergey Petrunia mendeskripsikan 3
MySQL
algoritma penyortiran dengan urutan kecepatanMySQL
di: http://s.petrunia.net/blog/?m=201407filesort()
pada tabel 1 tidak konstanfilesort()
di atasnyaDari definisi tabel dan gabungan yang ditunjukkan di atas, Anda dapat melihat bahwa Anda tidak akan pernah mendapatkan yang tercepat . Itu berarti Anda akan bergantung pada
filesort()
kriteria penyortiran yang Anda gunakan.Namun, jika Anda mendesain dan menggunakan Tampilan Terwujud Anda akan dapat menggunakan algoritma pengurutan tercepat.
Untuk
MySQL 5.5
(dalam contoh ini) untuk meningkatkanORDER BY
kecepatan jika Anda tidak bisaMySQL
menggunakan indeks daripada fase penyortiran tambahan, cobalah strategi berikut:• Meningkatkan nilai
sort_buffer_size
variabel.• Meningkatkan nilai
read_rnd_buffer_size
variabel.• Gunakan lebih sedikit RAM per baris dengan mendeklarasikan kolom hanya sebesar yang dibutuhkan untuk menyimpan nilai aktual. [Mis. Mengurangi varchar (256) menjadi varchar (ActualLongestString)]
• Ubah
tmpdir
variabel sistem untuk menunjuk ke sistem file khusus dengan sejumlah besar ruang kosong. (Detail lainnya ditawarkan dalam tautan di atas.)Tampilan Terwujud - Pendekatan Berbeda untuk Menyortir Tabel yang Bergabung
Anda menyinggung Tampilan Terwujud dengan pertanyaan Anda merujuk menggunakan pemicu. MySQL tidak memiliki fungsionalitas bawaan untuk membuat Tampilan Terwujud tetapi Anda memiliki alat yang diperlukan. Dengan menggunakan pemicu untuk menyebarkan beban, Anda dapat mempertahankan Tampilan Terwujud hingga saat ini.
Tampilan Terwujud sebenarnya adalah tabel yang diisi melalui kode prosedural untuk membangun atau membangun kembali Tampilan Terwujud dan dikelola oleh pemicu untuk menjaga data tetap up-to-date.
Karena Anda sedang membangun sebuah tabel yang akan memiliki indeks , maka Materialized View Ketika ditanya dapat menggunakan urutan tercepat : Gunakan metode akses berbasis indeks yang memproduksi output memerintahkan
Karena
MySQL 5.5
penggunaan pemicu untuk mempertahankan Tampilan Terwujud , Anda juga akan memerlukan proses, skrip, atau prosedur tersimpan untuk membangun Tampilan Terwujud awal .Tapi itu jelas proses yang terlalu berat untuk dijalankan setelah setiap pembaruan ke tabel dasar tempat Anda mengelola data. Di situlah pemicu berperan untuk menjaga data tetap mutakhir saat perubahan dilakukan. Dengan cara ini masing-masing
insert
,,update
dandelete
akan menyebarkan perubahannya, menggunakan pemicu Anda, ke Tampilan Terwujud .Organisasi FROMDUAL di http://www.fromdual.com/ memiliki kode sampel untuk mempertahankan Tampilan Terwujud . Jadi, daripada menulis sampel saya sendiri, saya akan mengarahkan Anda ke sampel mereka:
http://www.fromdual.com/mysql-materialized-views
Contoh 1: Membangun Tampilan Terwujud
Ini memberi Anda Tampilan Terwujud pada saat refresh. Namun, karena Anda memiliki basis data yang bergerak cepat, Anda juga ingin menjaga pandangan ini tetap terbaru.
Oleh karena itu tabel data dasar yang terpengaruh harus memiliki pemicu untuk menyebarkan perubahan dari tabel dasar ke tabel Tampilan Terwujud. Sebagai satu contoh:
Contoh 2: Memasukkan Data Baru Ke Tampilan Terwujud
Tentu saja, Anda juga akan memerlukan pemicu untuk mempertahankan Menghapus Data Dari Tampilan Terwujud dan Perbarui Data dalam Tampilan Terwujud . Sampel juga tersedia untuk pemicu ini.
TERAKHIR: Bagaimana Itu Membuat Penyortiran Meja Bergabung Lebih Cepat?
Tampilan Terwujud sedang dibangun terus-menerus karena pembaruan dibuat untuk itu. Oleh karena itu Anda dapat menentukan Indeks (atau Indeks ) yang ingin Anda gunakan untuk menyortir data dalam Tampilan atau Tabel Terwujud .
Jika overhead dari pemeliharaan data tidak terlalu berat, maka Anda menghabiskan beberapa sumber daya (CPU / IO / dll) untuk setiap perubahan data yang relevan untuk menjaga Tampilan Terwujud dan dengan demikian data indeks up-to-date dan tersedia. Karena itu, pilih akan lebih cepat, karena Anda:
Tergantung pada keadaan Anda dan bagaimana perasaan Anda tentang proses keseluruhan, Anda mungkin ingin membangun kembali Tampilan Terwujud setiap malam selama periode yang lambat.
sumber
Tidak banyak yang bisa dibahas di sini, tapi saya kira masalah utamanya adalah Anda membuat tabel sementara yang cukup besar dan mengurutkan file pada disk setiap kali. Alasannya adalah:
Ini berarti bahwa tabel temporer dan file sortir Anda bisa cukup besar, seperti saat membuat tabel sementara bidang dibuat pada panjang MAX, dan ketika menyortir catatan semua pada panjang MAX (dan UTF8 adalah 3 byte per karakter). Ini juga kemungkinan menghalangi penggunaan tabel sementara dalam memori. Untuk info lebih lanjut, lihat detail tabel temp internal .
LIMIT juga tidak ada gunanya bagi kita di sini, karena kita perlu mematerialisasikan dan memesan seluruh hasil yang ditetapkan sebelum kita tahu apa 3 baris pertama.
Sudahkah Anda mencoba memindahkan tmpdir Anda ke sistem file tmpfs ? Jika / tmp belum menggunakan tmpfs (MySQL menggunakan
tmpdir=/tmp
secara default pada * nix), maka Anda bisa menggunakan / dev / shm secara langsung. Dalam file my.cnf Anda:Maka Anda perlu me-restart mysqld.
Itu bisa membuat perbedaan besar . Jika Anda cenderung berada di bawah tekanan memori pada sistem, Anda mungkin ingin membatasi ukurannya (biasanya distro linux membatasi tmpfs pada 50% dari total RAM secara default) untuk menghindari pertukaran segmen memori ke disk, atau bahkan lebih buruk dari situasi OOM . Anda dapat melakukannya dengan mengedit baris di
/etc/fstab
:Anda juga dapat mengubah ukurannya "online". Sebagai contoh:
Anda juga dapat memutakhirkan ke MySQL 5.6 - yang memiliki subkueri berkinerja tinggi dan tabel turunan - dan bermain-main dengan kueri sedikit lebih banyak. Saya tidak berpikir kita akan melihat kemenangan besar melalui rute itu, dari apa yang saya lihat.
Semoga berhasil!
sumber