Masalahnya adalah pengelompokan itu berdasarkan name
membuat Anda kehilangan sales_id
informasi, oleh karena itu MySQL terpaksa menggunakan tabel sementara.
Meskipun ini bukan solusi terbersih, dan salah satu pendekatan yang kurang saya sukai, Anda dapat menambahkan indeks baru, di keduanya name
dan sales_id
kolom, seperti:
ALTER TABLE `yourdb`.`ycs_products`
ADD INDEX `name_sales_id_idx` (`name` ASC, `sales_id` ASC);
dan memaksa kueri untuk menggunakan indeks ini, dengan force index
atau use index
:
SELECT SQL_NO_CACHE p.name, COUNT(1) FROM ycs_sales s
INNER JOIN ycs_products p use index(name_sales_id_idx) ON s.id = p.sales_id
WHERE s.dtm BETWEEN '2018-02-16 00:00:00' AND '2018-02-22 23:59:59'
GROUP BY p.name;
Eksekusi saya hanya melaporkan "menggunakan di mana; menggunakan indeks" di tabel p dan "menggunakan di mana" di tabel s.
Bagaimanapun, saya sangat menyarankan Anda untuk memikirkan kembali skema Anda, karena mungkin Anda mungkin menemukan beberapa desain yang lebih baik untuk dua tabel ini. Di sisi lain, jika ini bukan bagian penting dari aplikasi Anda, Anda dapat menangani indeks "paksa".
EDIT
Karena cukup jelas bahwa masalahnya ada pada desain, saya sarankan untuk menggambar hubungan sebagai banyak-ke-banyak. Jika Anda memiliki kesempatan untuk memverifikasinya ke dalam lingkungan pengujian Anda, inilah yang akan saya lakukan:
1) Buat tabel sementara hanya untuk menyimpan nama dan id produk:
create temporary table tmp_prods
select min(id) id, name
from ycs_products
group by name;
2) Mulai dari tabel sementara, gabung dengan tabel penjualan untuk membuat pengganti ycs_product
:
create table ycs_products_new
select * from tmp_prods;
ALTER TABLE `poc`.`ycs_products_new`
CHANGE COLUMN `id` `id` INT(11) NOT NULL ,
ADD PRIMARY KEY (`id`);
3) Buat tabel gabungan:
CREATE TABLE `prod_sale` (
`prod_id` INT(11) NOT NULL,
`sale_id` INT(11) NOT NULL,
PRIMARY KEY (`prod_id`, `sale_id`),
INDEX `sale_fk_idx` (`sale_id` ASC),
CONSTRAINT `prod_fk`
FOREIGN KEY (`prod_id`)
REFERENCES ycs_products_new (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `sale_fk`
FOREIGN KEY (`sale_id`)
REFERENCES ycs_sales (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
dan isi dengan nilai yang ada:
insert into prod_sale (prod_id, sale_id)
select tmp_prods.id, sales_id from ycs_sales s
inner join ycs_products p
on p.sales_id=s.id
inner join tmp_prods on tmp_prods.name=p.name;
Terakhir, kueri bergabung:
select name, count(name) from ycs_products_new p
inner join prod_sale ps on ps.prod_id=p.id
inner join ycs_sales s on s.id=ps.sale_id
WHERE s.dtm BETWEEN '2018-02-16 00:00:00' AND '2018-02-22 23:59:59'
group by p.id;
Harap perhatikan bahwa grup menurut ada di kunci utama, bukan namanya.
Jelaskan keluaran:
explain select name, count(name) from ycs_products_new p inner join prod_sale ps on ps.prod_id=p.id inner join ycs_sales s on s.id=ps.sale_id WHERE s.dtm BETWEEN '2018-02-16 00:00:00' AND '2018-02-22 23:59:59' group by p.id;
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+
| 1 | SIMPLE | p | index | PRIMARY | PRIMARY | 4 | NULL | 3 | |
| 1 | SIMPLE | ps | ref | PRIMARY,sale_fk_idx | PRIMARY | 4 | test.p.id | 1 | Using index |
| 1 | SIMPLE | s | eq_ref | PRIMARY,dtm | PRIMARY | 4 | test.ps.sale_id | 1 | Using where |
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+