Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/72.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
Php 具有大型表的嵌套mysql查询_Php_Mysql_Sql - Fatal编程技术网

Php 具有大型表的嵌套mysql查询

Php 具有大型表的嵌套mysql查询,php,mysql,sql,Php,Mysql,Sql,我正在为一家小型图书馆设计一个管理系统。我建议他们用PhpMyBibli这样更强大、更专业的东西来取代目前使用的Excel电子表格,但他们害怕填写的字段太多,而且界面也没有完全翻译成意大利语 所以我制作了一个非常简单的数据库,基本上有一个供作者使用的表和一个供书籍使用的表。作者表是因为我已经厌倦了解释“Gabriele D'Annunzio”!=“加布里埃尔·德阿南佐”!=“Dannunzio G.”等等 我的测试表中现在有约10万本书和约3万名作者,都有看似合理的随机文本,用于在压力下检查脚本

我正在为一家小型图书馆设计一个管理系统。我建议他们用PhpMyBibli这样更强大、更专业的东西来取代目前使用的Excel电子表格,但他们害怕填写的字段太多,而且界面也没有完全翻译成意大利语

所以我制作了一个非常简单的数据库,基本上有一个供作者使用的表和一个供书籍使用的表。作者表是因为我已经厌倦了解释
“Gabriele D'Annunzio”!=“加布里埃尔·德阿南佐”!=“Dannunzio G.”
等等

我的测试表中现在有约10万本书和约3万名作者,都有看似合理的随机文本,用于在压力下检查脚本

对于公众咨询,我想制作一个类似Gallica的界面,Gallica是法国国家图书馆的网站,我觉得它非常有用。这里可以看到一个示例:

这个概念非常简单:对于每个菜单,例如author one,我都会生成一个奇特的
字段,其中包含从数据库中检索到的所有名称,这样做很顺利

当我试图在每个作者姓名旁边添加Gallica制作的书籍数量时,问题就出现了(警告-概念代码,而不是实际的PHP):

从作者处选择id、姓氏和姓名
每行{
从id\u auth=id的书籍中选择COUNT(*)作为num
echo“$姓氏,$name($num)”;
}
CPU核心上的代码以100%的速度跳转,浏览器中不会显示任何结果。这并不奇怪,因为它们在很短的时间内就完成了100k表上的3k查询

为了尝试,我在第一个查询(在authors表上)中添加了限制100。然后页面需要3秒才能生成,当我将限制提高到500秒时需要15秒(似乎是线性增量)。当然,我不能向图书馆用户展示一份减少的作者名单

我不知道Gallica使用了哪些硬件/软件来实现他们的成果,但我打赌他们的预算远远高于使用二手电脑的小村庄图书馆的预算

您认为在authors表中添加“number_of_books”字段(每次插入新书时都会更新)可能是一个实用的解决方案,而不是每次请求都浏览整个列表吗


顺便说一句,必须对发布日期、语言、主题和其他一些字段执行类似的过程,因此,即使其他表比作者的表小得多,查询时间也会再次被命中。

您的查询样式效率很低-请尝试使用连接和分组结构:

SELECT 
  authors.id, 
  authors.surname, 
  authors.name,
  COUNT(books.id) AS numbooks
FROM authors
INNER JOIN books ON books.id_auth=authors.id
GROUP BY authors.id
ORDER BY numbooks DESC
;
编辑

为了澄清一些问题,我没有明确地说:

  • 当然,您不再需要PHP循环中的查询,只需要显示部分
  • 假定
    books.id\u auth
    authors.id
    (后者主要或唯一)上的索引
编辑2

正如@GordonLinoff指出的,
IFNULL()
在内部连接中是多余的,所以我删除了它

要获取所有主题,即使其中没有任何书籍,也只需使用左连接(这一次包括
IFNULL()
,如果您的提供商的MySQL可能是旧的):

编辑3

当然,存储值将为您提供最佳性能—但这种非规范化是有代价的:您的数据库现在有可能以用户可见的方式变得不一致。 如果你用这种方法。我强烈建议您使用触发器自动填充此字段(当然,这些触发器必须位于books表上)。
准备好看到缓慢的插入-这当然可以,因为我猜您将看到
选择的比率比
插入的比率高得多
您的查询样式效率非常低-尝试使用连接和组结构

SELECT 
  authors.id, 
  authors.surname, 
  authors.name,
  COUNT(books.id) AS numbooks
FROM authors
INNER JOIN books ON books.id_auth=authors.id
GROUP BY authors.id
ORDER BY numbooks DESC
;
编辑

为了澄清一些问题,我没有明确地说:

  • 当然,您不再需要PHP循环中的查询,只需要显示部分
  • 假定
    books.id\u auth
    authors.id
    (后者主要或唯一)上的索引
编辑2

正如@GordonLinoff指出的,
IFNULL()
在内部连接中是多余的,所以我删除了它

要获取所有主题,即使其中没有任何书籍,也只需使用左连接(这一次包括
IFNULL()
,如果您的提供商的MySQL可能是旧的):

编辑3

当然,存储值将为您提供最佳性能—但这种非规范化是有代价的:您的数据库现在有可能以用户可见的方式变得不一致。 如果你用这种方法。我强烈建议您使用触发器自动填充此字段(当然,这些触发器必须位于books表上)。
准备好看到较慢的插入-这当然可以,因为我猜在阅读了大量关于JOIN语句如何工作的相关知识后,在 我发现我在15或20年前用过它,后来我忘了,因为我再也不需要它了

我使用我拥有的选项进行了测试:

  • 使用IFNULL()回复连接查询:0,5秒
  • 使用不带IFNULL()的联接查询进行答复:0,5秒
  • 使用存储值回复:0,4秒
该数据库将在一些单核旧熨斗上运行,因此我认为20%的差异可能非常显著,我决定使用存储值,每次插入新书时(即不经常)更新计数

无论如何,非常感谢您刷新了我的内存:在我的数据库中的其他地方,加入查询将非常有用


更新

我使用上面的JOIN方法查询书籍主题,这些主题存储在一个小得多的表中,方式如下:

选择theme.id、theme.main、theme.sub、COU
SELECT
  theme.id,
  theme.main,
  theme.sub,
  IFNULL(COUNT(books.theme),0) AS num
FROM themes
LEFT JOIN books ON books.theme=theme.id
GROUP BY themes.id
;