【问题标题】:how to optimize mysql query : counting category and subcategory with single Query from two tables如何优化 mysql 查询:使用两个表中的单个查询计算类别和子类别
【发布时间】:2012-07-10 18:22:10
【问题描述】:

我需要帮助来优化这个 MySQL 查询以获得更好和更快的性能。

这是带有查询和表结构的SQL FIDDLE

基本上我有两张桌子

tbl_category

CREATE TABLE IF NOT EXISTS `tbl_category` (
  `category_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `category_name` varchar(20) NOT NULL,
  `parent_category_id` int(10) unsigned DEFAULT NULL,      
  PRIMARY KEY (`category_id`),
  UNIQUE KEY `category_name` (`category_name`,`parent_category_id`),
  KEY `category_parent_id` (`parent_category_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

--
-- data for table `tbl_auction`
-- 
+-------------+---------------+--------------------+-----------------+
| category_id | category_name | parent_category_id | category_status | 
+-------------+---------------+--------------------+-----------------+
|           1 | Boats         |               NULL | a               | 
|           2 | Books         |               NULL | a               | 
|           3 | Building      |               NULL | a               | 
|           4 | Cars          |               NULL | a               | 
|           5 | Electrical    |                  3 | a               | 
|           6 | Hardware      |                  3 | a               | 
|           7 | Heating       |                  3 | a               | 
|           8 | Miscellaneous |                  3 | a               | 
|           9 | Plumbing      |                  3 | a               | 
|          10 | Tools         |                  4 | a               | 
|          11 | Lights        |                  4 | a               | 
|          12 | Miscellaneous |                  4 | a               | 
+-------------+---------------+--------------------+-----------------+

tbl_auction

CREATE TABLE IF NOT EXISTS `tbl_auction` (
  `auction_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
  `auction_category` int(10) unsigned NOT NULL 
   COMMENT 'either store subcategory OR main category if no subcategory',
  `auction_title` varchar(100) NOT NULL,     
  PRIMARY KEY (`auction_id`),
  KEY `auction_category` (`auction_category`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

--
-- data for table `tbl_auction`
--

+------------+------------------+---------------+
| auction_id | auction_category | auction_title | 
+------------+------------------+---------------+-
|          1 |                1 | one           | 
|          2 |                2 | two           | 
|          3 |                5 | five          | 
|          4 |                6 | six           | 
|          5 |                5 | five2         | 
|          6 |                8 | eight         | 
|          7 |               11 | eleven        | 
|          8 |               11 | eleven2       | 
|          9 |               10 | ten           | 
|         10 |                2 | two2          | 
|         11 |               12 | twelve        | 
+------------+------------------+---------------+

现在我想计算所有拍卖类别,以及如果某个类别有子类别,然后将该拍卖与主类别相加

我做了以下查询

SELECT auction_category AS categoryID, COUNT(*) AS total
      FROM `tbl_auction`
      GROUP BY auction_category
UNION ALL
SELECT parent_category_id  AS categoryID, COUNT( * ) AS total
      FROM  `tbl_auction` ta
      INNER JOIN tbl_category tc ON tc.category_id = ta.auction_category
      WHERE parent_category_id IS NOT NULL
      GROUP BY parent_category_id

虽然上面的查询返回了预期的结果但是我认为可能有一些优化的方法来解决这个问题。请指导我并建议我优化查询。

谢谢

【问题讨论】:

  • 您能否确认您不希望将拍卖计数两次:第一次在其自己的类别中,第二次在其父类别中(如果存在)?并且,您能否在 tbl_auction 中有这个案例:(9,“黄金厕所”)和(3,“梦想之家”)。如果是,您的查询是错误的。否则它对我来说看起来很完美并且经过适当优化。
  • 没有。如果有任何类别的子类别,则不能选择该类别,例如。 category_id = 3 具有子类别,然后 3 在插入 tbl_auction 时无法选择,因此无论如何 (9, 'Gold Toilet') and (3, 'Dream House'). 是不可能的
  • 我认为UNIONUNION ALL 更好
  • 这个区别真的是感觉不到的。即使是这样,UNION 会删除重复项,而UNION ALL 不会,所以我猜UNION ALL 的性能更高。并且由于黄金厕所梦想之家的情况不可能两者都给出相同的结果。

标签: mysql query-optimization


【解决方案1】:

杀死性能的是GROUP BYs 和/或UNION 之一触发的文件排序。您可以将不带UNION 的查询重写为:

SELECT pcat.category_id, COUNT(*)
  FROM  tbl_category pcat
  LEFT JOIN tbl_category subcat 
    ON subcat.parent_category_id = pcat.category_id 
  INNER JOIN tbl_auction a 
    ON a.auction_category = IFNULL(subcat.category_id,pcat.category_id)
GROUP BY pcat.category_id;

这具有相同的效果(重复计算每次拍卖,一次在其子猫下,一次在父猫下),并且EXPLAIN 显示没有文件排序。如果数据变大时出现这种情况,您可以尝试添加ORDER BY NULL 技巧。

此外,如果实时准确性不是特别重要但查询执行频繁,请考虑缓存结果。

【讨论】:

    猜你喜欢
    • 2012-02-20
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多