Problém je v seskupování podle name
ztratíte sales_id
informace, proto je MySQL nuceno používat dočasnou tabulku.
Ačkoli to není nejčistší z řešení a jeden z mých méně oblíbených přístupů, můžete přidat nový index na obě name
a sales_id
sloupce, jako:
ALTER TABLE `yourdb`.`ycs_products`
ADD INDEX `name_sales_id_idx` (`name` ASC, `sales_id` ASC);
a vynutit dotaz použít tento index, buď s force index
nebo 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;
Moje provedení hlásilo pouze "použití kde; pomocí indexu" v tabulce p a "použití kde" v tabulce s.
Každopádně vám důrazně doporučuji, abyste přehodnotili své schéma, protože pravděpodobně byste mohli najít lepší design pro tyto dvě tabulky. Na druhou stranu, pokud to není kritická část vaší aplikace, můžete se vypořádat s „vynuceným“ indexem.
UPRAVIT
Protože je zcela jasné, že problém je v návrhu, navrhuji nakreslit vztahy jako mnoho k mnoha. Pokud máte možnost to ověřit ve svém testovacím prostředí, udělal bych toto:
1) Vytvořte dočasnou tabulku pouze pro uložení názvu a ID produktu:
create temporary table tmp_prods
select min(id) id, name
from ycs_products
group by name;
2) Počínaje dočasnou tabulkou se připojte k prodejní tabulce a vytvořte náhradu za 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) Vytvořte spojovací tabulku:
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);
a vyplňte jej stávajícími hodnotami:
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;
Nakonec spojovací dotaz:
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;
Vezměte prosím na vědomí, že skupina podle je na primárním klíči, nikoli na jméně.
Vysvětlete výstup:
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 |
+------+-------------+-------+--------+---------------------+---------+---------+-----------------+------+-------------+