优化包含重复查询作为子查询的MySQL查询?

时间:2016-07-18 12:05:58

标签: mysql sql

假设我有这个问题:

(SELECT pets.id, "pets" AS "table" FROM pets WHERE name="Joey")
UNION ALL
(SELECT toys.id, "toys" AS "table" FROM (SELECT id, "pets" AS "table" FROM pets WHERE name="Joey") AS parentQuery, toys WHERE type="Ball" AND pet_id=parentQuery.id)
UNION ALL
(SELECT owners.id, "owners" AS "table" FROM (SELECT id, "pets" AS "table" FROM pets WHERE name="Joey") AS parentQuery, owners WHERE name="Issac" AND pet_id=parentQuery.id)

SQL小提琴:http://sqlfiddle.com/#!9/1637a/1

这里的想法是在多个一对多场景中获取相关行的ID列。 几个问题:

  1. 虽然我希望MySQL在某种程度上通过查询缓存优化,将相同的初始查询结果作为子查询嵌入到其他UNION'ed查询中,是否可以安全地进行查询干净地使用 SQL变量 (或其他东西)来引用其他查询中第一个查询的结果...以避免再次重复查询和任何捆绑参数每个额外的UNION'ed查询?
  2. (可选)如果您认为这是糟糕/鲁莽的SQL设计,请告诉我。我确信这可以通过JOIN变体来完成,但是我不确定是否会通过大量连接来提高性能,而不仅仅是像这样分割它?我听到了不同的意见。
  3. 谢谢!我已经看到了这个响应并且认为类似的东西可以工作,但是我到目前为止一般都避免使用SQL变量,因此我不确定如何使用UNION'ed查询来构建它:{{3} }

1 个答案:

答案 0 :(得分:0)

我想补充一些其他内容。

1)使用inner join转换您的查询。

  

我个人认为INNER JOIN更好,因为它更多   可读。 它更好地显示了表格之间的关系。你得到了   在连接中的那些关系,并在WHERE中进行过滤   条款。这种分离使查询更具可读性。但这是一个   个人品味问题。

因此,根据此选择,您转换后的查询:

SELECT 
    pets.id, 
    "pets" AS "table" 
FROM pets 
WHERE name= "Joey" 

UNION ALL

SELECT 
    owners.id,
    "pets" AS "table"
FROM pets 
INNER JOIN owners ON pets.id = owners.pet_id
WHERE pets.`name` = "Joey"
AND owners.`name`= "Issac"

UNION ALL

SELECT 
    toys.id,
    "toys" AS "table"
FROM toys 
INNER JOIN pets ON toys.pet_id = pets.id
WHERE pets.Name="Joey"
AND toys.type="Ball";

2)虽然您当前的查询效果不错,但我认为您可以通过在表格中创建一些composite index来提升效果。

  • pets表需要name,id上的综合索引。
  • toys表需要pet_id,type上的综合索引。
  • owners表需要pet_id,name上的综合索引。

修改

以下是创建了上述索引的三个表的表结构。

-- ----------------------------
-- Table structure for `owners`
-- ----------------------------
DROP TABLE IF EXISTS `owners`;
CREATE TABLE `owners` (
  `id` bigint(20) DEFAULT NULL,
  `pet_id` bigint(20) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  KEY `Idx_owners_pet_id_name` (`pet_id`,`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- ----------------------------
-- Table structure for `pets`
-- ----------------------------
DROP TABLE IF EXISTS `pets`;
CREATE TABLE `pets` (
  `id` bigint(20) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  KEY `Idx_pets_name_pet_id` (`name`,`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `toys`
-- ----------------------------
DROP TABLE IF EXISTS `toys`;
CREATE TABLE `toys` (
  `id` bigint(20) DEFAULT NULL,
  `pet_id` bigint(20) DEFAULT NULL,
  `type` varchar(255) DEFAULT NULL,
  KEY `Idx_toys_pet_id_type` (`pet_id`,`type`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

注意:稍后您可以按EXPLAIN (MySQL)检查查询效果。确保这三个表中有大量数据。 因为您无法判断小数据集的效果