我需要计算来自不同(!)表的行数并保存某些统计信息的结果。该脚本非常简单并且按预期工作,但我想知道是否更好地使用单个查询(在这种情况下)8个子查询,或者我是否应该使用单独的8个查询,或者是否有更好,更快和更多先进的解决方案......
我正在使用带有预处理语句的MySQLi,因此单个查询可能如下所示:
$sql = 'SELECT
(SELECT COUNT(cat1_id) FROM `cat1`),
(SELECT COUNT(cat2_id) FROM `cat2`),
(SELECT COUNT(cat2_id) FROM `cat2` WHERE `date` >= DATE(NOW())),
(SELECT COUNT(cat3_id) FROM `cat3`),
(SELECT COUNT(cat4_id) FROM `cat4`),
(SELECT COUNT(cat5_id) FROM `cat5`),
(SELECT COUNT(cat6_id) FROM `cat6`),
(SELECT COUNT(cat7_id) FROM `cat7`)';
$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($var1, $var2, $var3, $var4, $var5, $var6, $var7, $var8);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
虽然单独的查询看起来像这样(x 8):
$sql = 'SELECT
COUNT(cat1_id)
FROM
`cat1`';
$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($var1);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
所以,这种查询会更快或更“风格”(例如统计数据,计数器......)
答案 0 :(得分:0)
更好的方法是,只使用一个查询,因为只有一个带数据库的conecction,而不是,如果你使用很多查询,那么有很多带数据库的连接,这个过程包括:coneccting和disconeccting,这个更慢
答案 1 :(得分:0)
我倾向于在可能的情况下将查询放入FROM而不是SELECT。在此示例中,它需要表之间的交叉连接:
select c1.val, c2.val . . .
from (select count(cat1_id) as val from cat1) c1 cross join
(select count(cat2_id as val from cat2) c2 cross join
. . .
表现应该是一样的。但是,您的cat2表会显示优势:
select c1.val, c2.val, c2.valnow, . . .
from (select count(cat1_id) as val from cat1) c1 cross join
(select count(cat2_id) as val
count(case when date >= date(now()) then cat2_id end)
from cat2
) c2 cross join
. . .
通过不必扫描表两次以获得两个值,您可以节省大量成本。当您意识到您可能希望修改查询以返回多个值时,这也会有所帮助。
我相信交叉连接和select-within-select将具有相同的性能特征。真正确定的唯一方法是测试不同的版本。
答案 2 :(得分:0)
只是为了跟进你的评论,这是一个使用我的一个数据库的例子。在这里使用准备好的声明什么都不买。实际上,这个多查询只对D / B引擎执行一个RPC。所有其他调用都是PHP运行时系统的本地调用。
$db = new mysqli('localhost', 'user', 'password', 'blog');
$table = explode( ' ', 'articles banned comments config language members messages photo_albums photos');
foreach( $table as $t ) {
$sql[] = "select count(*) as count from blog_$t";
}
if ($db->multi_query( implode(';',$sql) )) {
foreach( $table as $t ) {
if ( ($rs = $db->store_result() ) &&
($row = $rs->fetch_row() ) ) {
$result[$t] = $row[0];
$rs->free();
$db->next_result(); // you must execute one per result set
}
}
}
$db->close();
var_dump( $result );
出于兴趣,我对此进行了strace
,相关的四行是
16:54:09.894296 write(4, "\211\1\0\0\3select count(*) as count fr"..., 397) = 397
16:54:09.895264 read(4, "\1\0\0\1\1\33\0\0\2\3def\0\0\0\5count\0\f?\0\25\0\0\0\10\201"..., 16384) = 544
16:54:09.896090 write(4, "\1\0\0\0\1", 5) = 5
16:54:09.896192 shutdown(4, 2 /* send and receive */) = 0
在查询和MySQLd进程的响应之间有大约1毫秒(这是因为这是在localhost上,结果是在它的查询缓存中,BTW)..并且0.8毫秒之后数据库关闭是执行。这是我4岁的笔记本电脑。
答案 3 :(得分:0)
关于TerryE的示例和使用multi_query(!)的建议,我检查了手册并更改了脚本以满足我的需要..最后我得到了一个如下所示的解决方案:
$sql = 'SELECT COUNT(cat1_id) as `cat1` FROM `cat1`;';
$sql .= 'SELECT COUNT(cat2_id) as `cat2` FROM `cat2`;';
$sql .= 'SELECT COUNT(cat2_id) as `cat2_b` FROM `cat2` WHERE `date` >= DATE(NOW());';
$sql .= 'SELECT COUNT(cat3_id) as `cat3` FROM `cat3`;';
$sql .= 'SELECT COUNT(cat4_id) as `cat4` FROM `cat4`;';
$sql .= 'SELECT COUNT(cat5_id) as `cat5` FROM `cat5`;';
$sql .= 'SELECT COUNT(cat6_id) as `cat6` FROM `cat6`;';
$sql .= 'SELECT COUNT(cat7_id) as `cat7` FROM `cat7`;';
if ($db->multi_query($sql))
{
do
{
if ($stmt = $db->store_result())
{
while ($row = $stmt->fetch_assoc())
{
foreach ($row as $key => $value)
{
$count[$key] = $value;
}
}
$stmt->free_result();
}
} while ($db->more_results() && $db->next_result());
}
TerryE的例子有一些不同,但结果是一样的。我知道开头有7行几乎相同,但只要我需要WHERE子句或其他东西,我更喜欢这个解决方案到foreach循环,我需要添加查询手动或使用if { ... }
...
据我所知,我的解决方案应该没有问题,或者我错过了什么?