Vấn đề là nhóm theo name
khiến bạn mất sales_id
thông tin, do đó MySQL buộc phải sử dụng bảng tạm thời.
Mặc dù đây không phải là giải pháp sạch nhất trong số các giải pháp và là một trong những cách tiếp cận ít được yêu thích hơn của tôi, bạn có thể thêm chỉ mục mới, trên cả hai tên name
và sales_id
các cột, như:
ALTER TABLE `yourdb`.`ycs_products`
ADD INDEX `name_sales_id_idx` (`name` ASC, `sales_id` ASC);
và lực lượng truy vấn để sử dụng chỉ mục này, với force index
hoặc 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;
Việc thực thi của tôi chỉ báo cáo "using where; using index" trên bảng p và "using where" trên bảng s.
Dù sao, tôi thực sự khuyên bạn nên suy nghĩ lại về lược đồ của mình, vì có thể bạn sẽ tìm thấy một số thiết kế tốt hơn cho hai bảng này. Mặt khác, nếu đây không phải là một phần quan trọng trong ứng dụng của bạn, bạn có thể xử lý chỉ mục "bắt buộc".
CHỈNH SỬA
Vì khá rõ ràng rằng vấn đề nằm trong thiết kế, tôi khuyên bạn nên vẽ các mối quan hệ dưới dạng nhiều-nhiều. Nếu bạn có cơ hội xác minh nó trong môi trường thử nghiệm của mình, đây là những gì tôi sẽ làm:
1) Tạo một bảng tạm thời chỉ để lưu trữ tên và id của sản phẩm:
create temporary table tmp_prods
select min(id) id, name
from ycs_products
group by name;
2) Bắt đầu từ bảng tạm thời, hãy tham gia bảng bán hàng để tạo bảng thay thế cho 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) Tạo bảng tham gia:
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);
và điền vào nó với các giá trị hiện có:
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;
Cuối cùng, truy vấn tham gia:
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;
Xin lưu ý rằng nhóm do nằm trên khóa chính, không phải tên.
Giải thích đầu ra:
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 |
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+