sql >> Database teknologi >  >> RDS >> Mysql

Optimer en forespørgsel, der grupperer resultater efter et felt fra den sammenføjede tabel

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


  1. Installation af eksempelskemaer til Oracle 12c ved hjælp af Database Configuration Assistant

  2. Hvorfor forbinder min .NET web-API-applikation ikke til MySQL på docker, når jeg bruger docker-compose?

  3. Skift fra JsonStringType til JsonBinaryType, når projektet bruger både MySQL og PostgreSQL

  4. Kontrollerer du en tabel for tidsoverlapning?