Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 从两个大表的联接中选择不同的值_Mysql_Sql_Performance_Join_Distinct - Fatal编程技术网

Mysql 从两个大表的联接中选择不同的值

Mysql 从两个大表的联接中选择不同的值,mysql,sql,performance,join,distinct,Mysql,Sql,Performance,Join,Distinct,我有一个animals表,有大约300万条记录。在其他几个列中,该表有一个id、name和owner\u id列。我有一个动物品种表,有大约250万条记录。该表只有动物id和品种列 我正在尝试查找与特定的所有者id关联的不同品种值,但查询大约需要20秒。问题是: 选择不同的品种` 来自“动物品种” 在'animals'上的内部连接'animals'。'id'='animal\u breeds'.'animal\u id' 其中'animals'。'owner_id`=; 这些表格都有适当的索引

我有一个
animals
表,有大约300万条记录。在其他几个列中,该表有一个
id
name
owner\u id
列。我有一个
动物品种
表,有大约250万条记录。该表只有
动物id
品种

我正在尝试查找与特定的
所有者id
关联的不同
品种
值,但查询大约需要20秒。问题是:

选择不同的品种`
来自“动物品种”
在'animals'上的内部连接'animals'。'id'='animal\u breeds'.'animal\u id'
其中'animals'。'owner_id`=;
这些表格都有适当的索引。我无法通过在
动物
表中添加
品种
列来反规范化该表,因为可以为动物分配多个品种。对于其他几个具有一对多关系的大型表,我也有这个问题

有没有更有效的方法来实现我所追求的目标?这似乎是一个非常简单的问题,但除了预计算和缓存结果之外,我似乎无法找到实现这一点的最佳方法

这是我查询的解释输出。注意使用临时的

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   "SIMPLE"    "a" NULL    "ref"   "PRIMARY,animals_animal_id_index"   "animals_animal_id_index"   "153"   "const" 1126303 100.00  "Using index; Using temporary"
1   "SIMPLE"    "ab"    NULL    "ref"   "animal_breeds_animal_id_breed_unique,animal_breeds_animal_id_index,animal_breeds_breed_index"  "animal_breeds_animal_id_breed_unique"  "5" "pedigreeonline.a.id"   1   100.00  "Using index"
根据要求,下面是createtable语句(我从
animals
表中删除了一些不相关的列和索引)。我相信
animal\u breeds\u animal\u id\u index
表上的
animal\u breeds
索引是多余的,因为表上有唯一的键,但我们现在可以忽略这一点,只要它没有引起问题:)

创建表“动物”(
`id`int(10)无符号非空自动增量,
`name`varchar(150)COLLATE utf8\u unicode\u ci NOT NULL,
`所有者\u id`varchar(50)校对utf8\u unicode\u ci默认为空,
主键(`id`),
关键字'animals\u animal\u id\u index'('owner\u id','id'),
键“动物名称索引”(“名称”),
)ENGINE=InnoDB自动增量=2470843默认字符集=utf8 COLLATE=utf8\U unicode\U ci
创建表“动物品种”(
`animal_id`int(10)无符号默认为空,
`繁殖'varchar(255)校对utf8mb4\u unicode\u ci非空,
唯一键'animal\u breeds\u animal\u id\u breed\u UNIQUE'('animal\u id','breed'),
关键“动物品种、动物id指数”(“动物id”),
关键“动物品种品种指数”(“品种”),
约束“animal\u breeds\u animal\u id\u foreign”外键(`animal\u id`)在更新级联的删除级联上引用“animals`”(`id`)
)ENGINE=InnoDB默认字符集=utf8mb4 COLLATE=utf8mb4\u unicode\u ci
任何帮助都将不胜感激。谢谢

对于此查询:

SELECT DISTINCT ab.`breed`
FROM `animal_breeds` ab INNER JOIN
     `animals` a
      ON a.`id` = ab.`animal_id` 
WHERE a.`owner_id` = ? ;
您需要有关
动物(所有者id,id)
动物品种(动物id,品种)
的索引。复合索引中列的顺序很重要

有了正确的索引,我想这将是非常快的

编辑:


根据解释,您使用的值有1126303个匹配项。时间是由于删除重复项。考虑到表的大小,会有这么多匹配一个值的表是令人惊讶的。

了解数据后,您可以尝试以下方法:

SELECT
    b.*
FROM
    (
        SELECT
            DISTINCT `breed`
        FROM
            `animal_breeds`
    ) AS b
WHERE
    EXISTS (
        SELECT
            *
        FROM
            animal_breeds AS ab
            INNER JOIN animals AS a ON ab.animal_id = a.id
        WHERE
            b.breed = ab.breed
            AND a.owner_id = ?
    )
;
...
WHERE
    b.breed IN (
        SELECT
            ab.breed
        FROM
            animal_breeds AS ab
            INNER JOIN animals AS a ON ab.animal_id = a.id
        WHERE
            a.owner_id = ?
    )
其思想是在不进行任何过滤的情况下获得不同品种的短列表(对于小列表,它将非常快),然后使用相关子查询进一步过滤列表。由于列表很短,因此只执行很少的子查询,它们只检查是否存在比任何分组(distinct==grouping)快得多的子查询

只有当您的独特列表很短时,这才有效

根据您的回答随机生成数据,上述查询为我提供了以下执行计划:

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   PRIMARY <derived2>      ALL                 2   100.00  
3   SUBQUERY    a       ref PRIMARY,animals_animal_id_index animals_animal_id_index 153 const   1011    100.00  Using index
3   SUBQUERY    ab      ref animal_breeds_animal_id_breed_unique,`animal_breeds_animal_id_index`,animal_breeds_animal_id_index  `animal_breeds_animal_id_index` 5   test.a.id   2   100.00  Using index
2   DERIVED animal_breeds       range   animal_breeds_animal_id_breed_unique,`animal_breeds_breed_index`,animal_breeds_breed_index  `animal_breeds_breed_index` 1022        2   100.00  Using index for group-by

谢谢你的信息。不幸的是,这两个组合键的顺序是一样的。我已经用我的
EXPLAIN
的输出更新了我的问题。它没有被命名为最佳,但“动物id”实际上是(动物id)。你确定你的索引吗?我没有看到在解释中的“a”上提到任何有所有者的索引。如果您提供show-create表输出,那就太好了。Gordon提到了索引(所有者id,id),而不是(动物id,id),这就是hudge的区别。@fifonik很抱歉混淆了,但我肯定是的。我在我的问题/评论中更改了一个列名(从“animal”改为“owner_id”),以使其在我的OP中稍微不那么混乱,但显然它只是增加了更多关于编辑的混乱:是的,
animal_breeds
表中有许多重复的品种值。约有250万种记录,但只有约250种独特品种。如果我在
animates
表上运行查询而不使用联接,那么查询只需要大约300毫秒,所以我不认为删除重复项需要时间?或者当使用连接与非连接时,重复删除技术是否会改变?我也不太清楚你所说的“有这么多匹配一个值的数据令人惊讶”是什么意思。你能解释一下吗?@Jeff。这与表中有多少品种无关。你的计划是建议一个主人在
动物品种中匹配超过一百万行。考虑到表的大小,这似乎太多了。CREATE TABLE语句最好用CREATE TABLE语句更新。点击键
animal\u breeds\u animal\u id\u index
animal\u id
),是的,我意识到这是多余的。自从编辑我的答案后,我已经把钥匙掉了,但是这并没有提高查询速度。谢谢!接下来几天我不在电脑前,但我认为这可能是一个完美的解决方案。我很快就会查出来,如果成功的话,我会把它标记为已解决。