簡體   English   中英

優化MySQL COUNT /按查詢分組:僅顯示與產品相關聯的類別

[英]Optimize MySQL COUNT / group by query: show only categories that have products associated

select COUNT(p.id) AS `num`, cat.id, cat.name, cat.parent_id AS `parent_id` 
from products p 
INNER JOIN `products_categories` AS `pc` ON p.id=pc.products_id 
INNER JOIN `categories` AS `cat` ON pc.categories_id=cat.id 
WHERE p.status = 1 AND p.gender IN ('female','neutral') 
group by cat.id

說明查詢:

1   SIMPLE  p   ref PRIMARY,gender,status   status  1   const   139107  Using where; Using temporary; Using filesort
1   SIMPLE  pc  ref products_id,categories  products_id 4   mydb.p.id   1   Using index
1   SIMPLE  cat eq_ref  PRIMARY,categoryname    PRIMARY 4   mydb.pc.categories_id   1   Using where

相關指標:

products    0   PRIMARY 1   id  A   299339              BTREE       
products    1   title   1   title   A   299339              BTREE       
products    1   sku 1   sku A   299339              BTREE       
products    1   body    1   body    A   299339  200         BTREE       
products    1   short_description   1   short_description   A   299339  200     YES BTREE       
products    1   keywords    1   keywords    A   2   200         BTREE       
products    1   gender  1   gender  A   10              BTREE       
products    1   status  1   status  A   2               BTREE       
products    1   brand_id    1   brand_id    A   3741            YES BTREE       
products    1   merchant    1   merchant_id A   52              BTREE       
products    1   title_2 1   title,body,keywords     299339              FULLTEXT        
products    1   title_3 1   title       299339              FULLTEXT        
products    1   body_2  1   body        299339              FULLTEXT        

products_categories 0   PRIMARY 1   id  A   514054              BTREE       
products_categories 1   products_id 1   products_id, categories_id  A   514054              BTREE           
products_categories 1   categories  1   categories_id   A   266             BTREE       

categories  0   PRIMARY 1   id  A   154             BTREE       
categories  1   categoryname    1   name    A   154             BTREE       

這是一個包含產品,類別和它們之間的N:N關系的數據庫。 產品可以是1個或多個類別。

我基本上需要一個查詢來告訴我,對於該類別當前是否具有任何產品(對於我來說,我可以隱藏沒有產品的類別),對於當前的產品過濾器(在本例中為狀態和性別)。 目前,我對每個類別中的產品進行計數以了解這一點。

查詢WHERE參數將根據用戶選擇的過濾器而變化,因此該部分在此優化中不是很重要。

我不需要類別中產品的確切數量,即使它們是否具有產品也是如此。 Products表具有很多索引,具有products_categories和category表。 產品表包含約40萬個產品,150個類別和50萬個product_categories。

MySQL 5.6.22托管在AWS RDS上,InnoDB中的所有表。

我了解我的解釋查詢顯示了為什么它運行緩慢(瀏覽了很多產品),但是我不知道如何優化它……也許是考慮問題的另一種方式?

對於此查詢:

select COUNT(p.id) AS `num`, cat.id, cat.name, cat.parent_id AS `parent_id` 
from products p INNER JOIN
     products_categories `pc`
     ON p.id = pc.products_id INNER JOIN
     categories cat
      ON pc.categories_id = cat.id 
WHERE p.status = 1 AND p.gender IN ('female', 'neutral') 
group by cat.id;

您需要所有join鍵上的索引。 我會推薦products(status, gender, id)products_categories(products_id, categories_id)categories(id)

有時,在MySQL中,使用相關子查詢比使用group by更快,方法group by

select c.*,
       (select count(*)
        from products_categories `pc` INNER JOIN
             products p
             ON p.id = pc.products_id
        where pc.categories_id = cat.id AND
              p.status = 1 AND p.gender IN ('female', 'neutral') 
       ) as cnt
from categories c;

這個版本需要在products_categories(categories_id, products_id)products(id, status, gender)上的索引。

您的查詢返回139107條匹配記錄,因為您使用的過濾條件不是很嚴格(狀態= 1,性別=女性或中性)。

SELECT cat.id, cat.name, cat.parent_id AS `parent_id`,
      COUNT(p.id) AS `num` 
FROM `categories` AS `cat`
INNER JOIN `products_categories` AS `pc` ON pc.categories_id=cat.id 
INNER JOIN products AS p ON p.id=pc.products_id 
WHERE p.status = 1 AND p.gender IN ('female','neutral') 
GROUP BY cat.id
HAVING COUNT(p.id)>0

添加HAVING不會自動改善查詢。 問題是您的過濾條件會返回許多匹配的產品。 按性別或布爾狀態(真/假)過濾記錄可能會導致表掃描,因為值重復很多,即使狀態和性別是索引,MySQL仍可能認為運行表掃描比使用索引便宜。

HAVING用於過濾沒有產品的任何類別。 嘗試這個

SELECT cat.id, cat.name, cat.parent_id AS `parent_id`,
      COUNT(pc._products_id) AS `num` 
FROM `categories` AS `cat`
INNER JOIN `products_categories` AS `pc` ON pc.categories_id=cat.id 
GROUP BY cat.id
HAVING COUNT(pc.products_id)>0

上面的查詢將不與產品表聯接。 如果它們具有產品關聯,則僅查看product_categories。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM