Mysql
 sql >> база данни >  >> RDS >> Mysql

Оптимизирайте заявка, която групира резултатите от поле от обединената таблица

Проблемът е, че групирането по name ви кара да загубите sales_id информация, следователно MySQL е принуден да използва временна таблица.

Въпреки че не е най-чистото от решенията и един от по-малко любимите ми подходи, можете да добавите нов индекс и за и двете name и sales_id колони, като:

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

исилата заявката за използване на този индекс с force index или 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;

Моето изпълнение отчете само „използване на where; използване на индекс“ в таблица p и „използване на where“ в таблица s.

Както и да е, силно ви предлагам да преосмислите схемата си, защото вероятно ще намерите по-добър дизайн за тези две таблици. От друга страна, ако това не е критична част от приложението ви, можете да се справите с „принудителния“ индекс.

РЕДАКТИРАНЕ

Тъй като е съвсем ясно, че проблемът е в дизайна, предлагам да нарисувате връзките като много към много. Ако имате възможност да го потвърдите във вашата среда за тестване, ето какво бих направил:

1) Създайте временна таблица само за съхраняване на името и идентификатора на продукта:

create temporary table tmp_prods
select min(id) id, name
from ycs_products
group by name;

2) Започвайки от временната таблица, присъединете се към таблицата за продажби, за да създадете заместител на 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) Създайте таблицата за присъединяване:

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);

и го попълнете със съществуващите стойности:

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;

И накрая, заявката за присъединяване:

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;

Моля, имайте предвид, че групата от е на първичния ключ, а не в името.

Обяснете изхода:

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. Отказ и отказ на Amazon RDS

  2. Как да промените събитие в mysql, което вече е създадено

  3. Изпълнете скрипт/команда на Shell от MySQL Trigger/Stored Procedure

  4. Как да накарам CakePHP bake, за да намеря mysql.sock и да разпозная MySQL, докато използвам MAMP на Mac OSX?

  5. Попълване на полета в модална форма с помощта на PHP, jQuery