php - 带有巨大表的嵌套 mysql 查询

标签 php mysql sql

我正在为一家小型图书馆开发管理系统。我建议他们用像 PhpMyBibli 这样更强大、更专业的东西替换他们现在使用的 Excel 电子表格 - https://en.wikipedia.org/wiki/PhpMyBibli - 但他们对要填写的字段数量感到害怕,而且界面没有完全翻译成意大利语。

所以我做了一个非常简单的数据库,基本上有一个作者表和一个书表。作者表是因为我厌倦了解释 "Gabriele D'Annunzio" != "Gabriele d'Annunzio" != "Dannunzio G."等等。

我的测试表现在有大约 10 万本书和大约 3000 位作者,它们都有看似合理的随机文本,以在压力下检查脚本。

对于公众咨询,我想制作一个类似 Gallica 的界面,法国国家图书馆 的网站,我觉得它非常有用。示例可在此处查看:http://gallica.bnf.fr/Search?ArianeWireIndex=index&p=1&lang=EN&f_typedoc=livre&q=Computer&x=0&y=0

这个概念很简单:对于每个菜单,例如作者一,我生成一个看中的<select>包含从数据库中检索到的所有名称的字段,这可以顺利进行。

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

SELECT id, surname, name FROM authors
foreach row {
    SELECT COUNT(*) as num FROM BOOKS WHERE id_auth=id
    echo "<option>$surname, $name ($num)</option>";
}

在上面的代码中,CPU 的一个核心以 100% 的速度跳转,浏览器中没有显示任何结果。不足为奇,因为它们是在很短的时间内对 100k 的表进行 3k 次查询。

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

我不知道 Gallica 使用哪种硬件/软件来实现他们的结果,但我敢打赌他们的预算远远高于使用 2 手电脑的小型乡村图书馆。

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

顺便说一句,必须对出版日期、语言、主题和其他一些字段执行类似的过程,因此查询时间将再次受到影响,即使其他表比作者的表小很多。

最佳答案

您的查询方式非常低效 - 尝试使用join and group 结构:

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_authauthors.id 上的索引(后者是主要的或唯一的)是假定的

编辑 2

正如@GordonLinoff 指出的那样,IFNULL() 在内部联接中是多余的,因此我将其删除。

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

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
;

编辑 3

当然,存储值将为您提供最佳性能 - 但这种非规范化是有代价的:您的数据库现在有可能以用户可见的方式变得不一致。 如果您确实使用此方法。我强烈建议您使用触发器来自动填充此字段(当然,这些触发器必须放在 books 表上)。 准备好看到减慢的插入 - 这当然没问题,因为我猜你会看到比 INSERTS

更高的 SELECTS

关于php - 带有巨大表的嵌套 mysql 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28844764/

相关文章:

php - 如何在 phpMyAdmin 中填充数据库的多个表

用于复制数据库及其所有表的 PHP 脚本

mysql - SQL 问题 : Inserting values into one clumn, 每个其他列中的 EMPTY 值数量相同

java - Criteria.list() 以 BatchUpdateException : Data truncation 结尾

mysql - 只有一个条件的一个查询中对多个表的多次更新

sql - NHibernate.Linq - 自定义/计算属性表达式

PHP 搭建多语言站点的最佳实践

php - 使用 MySQL 直接在查询中进行值检查

php - 内存泄漏?!在 'create_function' 中使用 'array_map' 时,垃圾收集器是否正常运行?

mysql - 如果 MySQL 上不存在则创建分区