在每个表数据中有超过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)){
}
}
结果更快? (我已将所有表格编入索引)
答案 0 :(得分:2)
与大多数数据库一样,答案取决于它。
首先,请注意两种查询模式的结果有很大不同。
作为一个例子,考虑当table_3
为空(不包含任何行)时会发生什么。使用JOIN查询模式,我们将不会得到任何结果......结果集将包含零行。
另一个查询,对每个表运行单独的查询,将从table_1
和table_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