Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Tối ưu hóa một truy vấn nhóm các kết quả theo một trường từ bảng đã kết hợp

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 namesales_id các cột, như:

ALTER TABLE `yourdb`.`ycs_products` 
ADD INDEX `name_sales_id_idx` (`name` ASC, `sales_id` ASC);

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 |
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL 8.0 - Máy khách không hỗ trợ giao thức xác thực do máy chủ yêu cầu; xem xét nâng cấp máy khách MySQL

  2. Nhiều bảng hay một bảng lớn trong SQL?

  3. Hiểu rõ hơn - Class.forName (com.mysql.jdbc.Driver) .newInstance ();

  4. MySQL - Đặt tên cột cho ID khi tạo?

  5. tải dữ liệu cục bộ trong tệp ERROR 2 không tìm thấy tệp