嵌套查询比连接查询更快吗?

时间:2018-05-03 18:20:34

标签: mysql sql join nested-queries

在每个表数据中有超过1万条记录。列出此数据时,查询结果会更快。嵌套查询比连接查询更快吗?

嵌套查询:

$query = $baglanti->prepare("Select * from table_1");
$query->execute();
if($query->rowCount() > 0){
    while($query_data=$query->fetch(PDO::FETCH_ASSOC)){
        $query_2 = $baglanti->prepare("Select * from table_2 where table_1_id = :id");
        $query_2->bindParam(":id", $query_data["id"], PDO::PARAM_INT);
        $query_2->execute();
        if($query_2->rowCount() > 0){
            while($query_2_data=$query_2->fetch(PDO::FETCH_ASSOC)){
                $query_3 = $baglanti->prepare("Select * from table_3 where table_2_id = :id");
                $query_3->bindParam(":id", $query_2_data["id"], PDO::PARAM_INT);
                $query_3->execute();
                if($query_3->rowCount() > 0){
                    while($query_3_data=$query_3->fetch(PDO::FETCH_ASSOC)){
                        table_4
                        table_5
                        ...
                    }
                }
            }
        }
    }
}

内部联接查询:

$query = $baglanti->prepare("Select * from table_1
    INNER join table_2
    on table_1.id=table_2.table_1_id
    INNER join table_3
    on table_2.id=table_3.table_2_id
    INNER join table_4
    on table_3.id=table_4.table_3_id
    INNER join table_5
    on table_4.id=table_5.table_4_id
    ...
    ");
$query->execute();
if($query->rowCount() > 0){
    while($query_data=$query->fetch(PDO::FETCH_ASSOC)){

    }
}

结果更快? (我已将所有表格编入索引)

2 个答案:

答案 0 :(得分:2)

与大多数数据库一样,答案取决于它。

首先,请注意两种查询模式的结果有很大不同。

作为一个例子,考虑当table_3为空(不包含任何行)时会发生什么。使用JOIN查询模式,我们将不会得到任何结果......结果集将包含零行。

另一个查询,对每个表运行单独的查询,table_1table_2返回行。

此外,使用JOIN模式,我们将从table_1,table_2返回冗余的数据副本......

但就“更快”而言,通常JOIN模式会更快,因为它消除了对数据库的大量往返。发送SQL,解析令牌,语义检查,开发执行计划,执行计划,准备结果集,将结果集返回给客户端,等待客户端进行提取,然后清理(关闭语句句柄和丢弃结果集。)

当数据库往返次数急剧增加时,每个语句执行的小开销就会开始显着增加。

好处是,通过简单的查询,往往需要考虑更少的执行路径,我们通常会为每个查询获得一个合理有效的计划(假设有合适的索引可用。

JOIN模式的风险在于我们可以生成一个非常大的集合,其中包括每行上的大量冗余数据。

让我们考虑一个场景:

如果我们在table_1中有1000行。

如果table_1中的每一行都有1,000行,那么table_1中的每一行。

如果我们在table_3中为table_2中的每一行都有100行。

如果table_3中的每一行在table_4中有10行。

如果table_4中的每一行table_5都有1行。

这里有一些快速数学... 10 ^ 3 ^ 10 ^ 3 * 10 ^ 2 * 10 ^ 1 * 10 ^ 0 = 10 ^ 9

这将导致结果集中有10亿行。 table_1中每行的数据将重复10 ^ 6次。这是相同table_1值的一百万份。

我们有可能产生“非常大”的结果集,并且相应地增加了资源需求,这可能会导致性能下降。

所以我们倾向于中间立场。我们更喜欢处理集合而不是处理RBAR(通过痛苦行划线),但我们也想避免使用Hugh Jass结果集。

可以在这两种方法之间的某处获得最佳性能。例如,通过在循环中处理table_1中的各个行,并对于检索到的每一行,我们对JOIN中的其余四个表运行查询以获取组合结果。

答案 1 :(得分:-3)

我会跳过计算机技术位并直接讨论无聊的MySQL实现细节,因为MySQL小组已经提出了这个问题。

在MySQL中,尤其是5.6之前,常量子查询尤其是坏消息。如果可能的话,我仍然会避开它们,除非你能以这样的方式编写它们,使它们在FROM列表中(而不是在WHERE中)。

问题是常量子查询结果(没有?)没有被缓存,因此每次WHERE子句访问它时,WHERE中的常量子查询将被完全评估;如果WHERE访问了一百万行,那么内部子查询将被完全评估一百万次,即使它的结果永远不会改变!

如果我无法重做查询以在FROM中使用子查询,我会重写此类查询以将子查询结果运行到临时内存表中并在" real&#中使用该表34;查询; 执行此操作的查询的性能提高了100倍或更多。

相关子查询 - 意味着对外部查询有引用的子查询 - 在MySQL中实际上并不是那么糟糕,所以如果EXISTS的子查询被正确编入索引,它通常可以正常工作。

如果子查询实际上可以重写为连接(大多数可以,但许多人可以,特别是EXISTS或产生聚合的子查询),它通常会在MySQL中表现更好。

但是,请始终使用EXPLAIN并了解您的查询计划中的内容,因为您的查询中的细微差别会产生巨大的差异。

参考:https://www.quora.com/Which-is-faster-joins-or-subqueries