Problemet er, at gruppering efter name
får dig til at miste sales_id
oplysninger, derfor er MySQL tvunget til at bruge en midlertidig tabel.
Selvom det ikke er den reneste af løsningerne, og en af mine mindre foretrukne tilgange, kan du tilføje et nyt indeks på begge name
og sales_id
kolonner, som:
ALTER TABLE `yourdb`.`ycs_products`
ADD INDEX `name_sales_id_idx` (`name` ASC, `sales_id` ASC);
og tvang forespørgslen til at bruge dette indeks med enten force index
eller 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;
Min udførelse rapporterede kun "bruger hvor; bruger indeks" på tabellen p og "bruger hvor" på tabellen s.
I hvert fald foreslår jeg kraftigt, at du genovervejer dit skema, fordi du sandsynligvis kan finde et bedre design til disse to tabeller. På den anden side, hvis dette ikke er en kritisk del af din ansøgning, kan du håndtere det "tvungne" indeks.
REDIGER
Da det er helt klart, at problemet ligger i designet, foreslår jeg, at man tegner relationerne som mange-til-mange. Hvis du har mulighed for at verificere det i dit testmiljø, er det her, jeg ville gøre:
1) Opret en midlertidig tabel bare for at gemme navn og id på produktet:
create temporary table tmp_prods
select min(id) id, name
from ycs_products
group by name;
2) Start fra den midlertidige tabel, tilmeld dig salgstabellen for at oprette en erstatning for 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) Opret jointabellen:
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);
og udfyld den med de eksisterende værdier:
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;
Til sidst, joinforespørgslen:
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;
Bemærk venligst, at gruppen efter er på den primære nøgle, ikke navnet.
Forklar output:
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 |
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+