哪个更快/更高效——大量的小 MySQL 查询或一个大的 PHP 数组?

Posted

技术标签:

【中文标题】哪个更快/更高效——大量的小 MySQL 查询或一个大的 PHP 数组?【英文标题】:Which is faster / more efficient - lots of little MySQL queries or one big PHP array? 【发布时间】:2012-08-16 14:10:11 【问题描述】:

我有一个基于 php/mysql 的 Web 应用程序,它通过名为 language_strings 的 MySQL 表提供国际化支持,其中包含 string_idlang_idlang_text 字段。

当我需要以所选语言显示字符串时,我调用以下函数:

public function get_lang_string($string_id, $lang_id)
    
        $db = new Database();
        $sql = sprintf('SELECT lang_string FROM language_strings WHERE lang_id IN (1, %s) AND string_id=%s ORDER BY lang_id DESC LIMIT 1', $db->escape($lang_id, 'int'), $db->escape($string_id, 'int'));
        $row = $db->query_first($sql);

        return $row['lang_string'];
    

这很好用,但我担心可能会有很多数据库查询正在进行。例如主菜单有5个链接文本,都调用这个函数。

将所选lang_id 的整个language_strings 表结果加载到PHP 数组中,然后从函数中调用它会更快吗?这可能是一个巨大的数组,其中大部分是冗余的,但显然它是每个页面加载一个数据库查询,而不是很多。

谁能提出另一种更有效的方法?

【问题讨论】:

您的查询以LIMIT 1 结尾,1 的数组可以有多大? @EliasVanOotegem 这就是我目前的代码,一次只检索一个,但该函数被多次调用。如果我在表中查询特定 lang_id 的所有记录,那么该数组将有 1000 条或更多记录。 至少对于您的应用程序的“静态”部分,例如 主菜单,我建议您使用缓存版本的菜单而不是查询数据库。比如menu.en.htmlmenu.de.html等。 【参考方案1】:

没有不区分大小写的答案。您可以根据具体情况逐个陈述。话虽如此,在大多数情况下,在一个查询中获取所有数据、将其弹出到数组或对象中并从那里引用它会更快。

需要注意的是,您能否像运行五个单独的查询一样快速地在一个查询中提取您需要的所有数据。这就是查询本身的性能发挥作用的地方。

有时一个包含一两个子查询的查询实际上比单独运行几个查询的时间效率低。

我的建议是测试一下。一起获取一个查询,获取你需要的所有数据,看看执行需要多长时间。对其他五个查询中的每一个进行计时,看看它们合并需要多长时间。如果几乎相同,将输出粘贴到一个数组中,这样效率会更高,因为不必频繁连接到数据库本身。

但是,如果您的组合查询需要更长的时间来返回数据(例如,它可能会导致全表扫描而不是使用索引),那么请坚持使用单个查询。

最后,如果您要一遍又一遍地使用相同数据 - 数组或对象将赢得每次的胜利,因为访问它会更快而不是从数据库中获取。

【讨论】:

如果只有 5 个查询,这不是问题。有时在一页上可能会调用 100 次或更多 get_lang_string 函数。 @PandyLegend 所以手动运行一些测试:) 通常,存储一次并在同一个地方使用它会更快,但就像我说的那样,在某些情况下它会导致初始查询要长得多(但这些都是根据具体情况进行的测试)。 谢谢。我认为这将是一个做一些基准测试并靠耳朵玩的案例。目前这不是问题,因为系统不忙,但我将来可能会非常忙,所以我现在必须权衡一下。感谢您的帮助。【参考方案2】:

好的 - 我做了一些基准测试,并惊讶地发现将事物放入数组而不是使用单个查询平均会慢 10-15%。

我认为这是因为,即使我过滤掉了“不常见”的元素,不可避免地总会有自然而然的元素。

对于单个查询,我只能得到我需要的内容,而且由于查询非常简单,我认为我最好坚持使用这种方法。

这对我有用,当然在个别查询更复杂的其他情况下,我认为将公共数据存储在数组中的方法会更有效。

【讨论】:

你如何访问内存中的数组?您没有在任何地方使用 array_key_exists() ,对吗?因为这个功能非常低效 @talkol 这是真的吗?测试哈希表键是否存在应该是低效的听起来很荒谬 - 这是一个应该在恒定时间内运行的操作。 您的数据库是否与 php 代码(即网络服务器)在同一台机器上运行?【参考方案3】:

同意这里的每个人所说的......这都是关于数字的。

一些额外的提示:

    尝试创建一个存储您所需最小值的单个内存阵列。这意味着删除大部分明显的冗余。

    在性能关键的环境中,有一些标准方法可以解决这些问题,例如将 memcached 与 mysql 结合使用。这有点矫枉过正,但这基本上可以让您分配一些外部内存并在那里缓存您的查询。由于您选择了要分配的内存量,因此您可以根据系统的内存量进行规划。

    只玩数字。尝试使用单独的查询(这是最简单的方法)并强调您的 PHP 脚本(例如从命令行调用它数百次)。测量这需要多少时间,看看实际性能损失有多大。根据我的个人经验,我通常将所有内容缓存在内存中,然后有一天当数据变得太大时,我会耗尽内存。然后我将所有内容拆分为单独的查询以节省内存,并首先看到性能影响并没有那么糟糕:)

【讨论】:

谢谢。关于第 1 点,我想也许我可以将所有常见的字符串加载到一个数组中(例如每个页面上需要的那些),然后只单独查询不常见的字符串。【参考方案4】:

我同意 Fluffeh 的意见:查看您可以使用的其他选项(连接、子查询,确保您的索引反映数据的相关性 - 但不要过度索引和 测试) .很可能你会在某个时候得到一个数组,所以这里有一个小的性能提示,与你所期望的相反,像

$all = $stmt->fetchAll(PDO::FETCH_ASSOC);

相比而言,内存效率也较低:

$all = array();//or $all = []; in php 5.4
while($row = $stmt->fetch(PDO::FETCH_ASSOC);

    $all[] = $row['lang_string '];

更重要的是:您可以在获取数据时检查冗余数据。

【讨论】:

【参考方案5】:

我的答案是在两者之间做点什么。检索 lang_id 的所有字符串,这些字符串短于某个长度(例如,100 个字符)。较短的文本字符串比较长的字符串更有可能在多个地方使用。将条目缓存在 get_lang_string() 中的静态关联数组中。如果未找到某个项目,则通过查询检索它。

【讨论】:

【参考方案6】:

我目前在我的site/application 中,我不得不踩刹车并非常仔细地考虑速度。我认为提到的这些速度测试应该将服务器上的流量视为影响结果的重要变量。如果您将数据放入 javascript 数据结构并在客户端计算机上处​​理,则处理时间应该更规律。如果您通过 mysql 通过 php 请求大量数据(例如),这是对一台机器/服务器的需求,而不是传播它。随着流量的增长,您必须与许多用户共享服务器资源,我认为这就是让 JavaScript 做更多事情的地方,这将减轻服务器上的负载。您还可以通过localstorage.setItem(); / localstorage.getItem(); 将数据存储在本地计算机中(大多数浏览器每个域大约有 5mb 的空间)。如果您的数据库中的数据不经常更改,那么您可以将其存储到客户端,然后在“启动”时检查它是否仍处于日期/有效状态。

这是我在拥有并使用该帐户 1 年后发表的第一条评论,因此我可能需要微调我的散漫 - 只是表达我目前的想法。

【讨论】:

以上是关于哪个更快/更高效——大量的小 MySQL 查询或一个大的 PHP 数组?的主要内容,如果未能解决你的问题,请参考以下文章

调用缓存图像时哪个更高效/更快?

MySQL,longtext、text 还是 blob 哪个更高效?提高插入效率

哪个更快:多行还是多列?

MySQL:在 1:N 关系中哪个更快?加入还是两个查询? [复制]

mysql分页原理和高效率的mysql分页查询语句

NetworkX和Graphscope哪个运算速度更快?