Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Optimalkan kueri yang mengelompokkan hasil berdasarkan bidang dari tabel yang digabungkan

Masalahnya adalah pengelompokan itu berdasarkan name membuat Anda kehilangan sales_id informasi, oleh karena itu MySQL terpaksa menggunakan tabel sementara.

Meskipun ini bukan solusi terbersih, dan salah satu pendekatan yang kurang saya sukai, Anda dapat menambahkan indeks baru, di keduanya name dan sales_id kolom, seperti:

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

dan memaksa kueri untuk menggunakan indeks ini, dengan force index atau 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;

Eksekusi saya hanya melaporkan "menggunakan di mana; menggunakan indeks" di tabel p dan "menggunakan di mana" di tabel s.

Bagaimanapun, saya sangat menyarankan Anda untuk memikirkan kembali skema Anda, karena mungkin Anda mungkin menemukan beberapa desain yang lebih baik untuk dua tabel ini. Di sisi lain, jika ini bukan bagian penting dari aplikasi Anda, Anda dapat menangani indeks "paksa".

EDIT

Karena cukup jelas bahwa masalahnya ada pada desain, saya sarankan untuk menggambar hubungan sebagai banyak-ke-banyak. Jika Anda memiliki kesempatan untuk memverifikasinya ke dalam lingkungan pengujian Anda, inilah yang akan saya lakukan:

1) Buat tabel sementara hanya untuk menyimpan nama dan id produk:

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

2) Mulai dari tabel sementara, gabung dengan tabel penjualan untuk membuat pengganti 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) Buat tabel gabungan:

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

dan isi dengan nilai yang ada:

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;

Terakhir, kueri bergabung:

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;

Harap perhatikan bahwa grup menurut ada di kunci utama, bukan namanya.

Jelaskan keluaran:

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. Bagaimana saya bisa mendapatkan id yang bertambah secara otomatis ketika saya memasukkan catatan ke dalam tabel melalui jdbctemplate

  2. Mengapa hanya ada satu kolom TIMESTAMP dengan CURRENT_TIMESTAMP dalam klausa DEFAULT?

  3. Tidak dapat mengakses database Sonar MySQL Disebabkan oleh:java.sql.SQLException:Akses ditolak untuk pengguna 'sonar'@'glassfishdev.ccs.local' (menggunakan kata sandi:YA)

  4. Haruskah diagram ER ini menggunakan hubungan ternary sebagai gantinya

  5. mysql_fetch_array() mengharapkan parameter 1 menjadi masalah sumber daya