如何使这个 mysqli 查询在 PHP 中运行得更快?

Posted

技术标签:

【中文标题】如何使这个 mysqli 查询在 PHP 中运行得更快?【英文标题】:How can i make this mysqli query run faster in PHP? 【发布时间】:2014-12-08 20:11:10 【问题描述】:

$networks 是具有多个值的字符串,以逗号分隔。 示例:

$networks = "Programming,Movies,Hollywood". (There can be around 150 values or more.)    

现在 mysql 查询到这里了:

$query = "SELECT * FROM table 
          WHERE ( isActive = 1 AND 
                  isDeleted = 0 AND 
                  onid = '0' AND 
                  question = 0 AND 
                  ( ".$networkqur." )
                ) 
ORDER BY id DESC
LIMIT 0,100;

这里 $networkqur 是:

$network = explode(',',$networks);

$networkqur = '';
for( $i = 0; $i < count($network); $i++ )
    $networkqur .= 'networks LIKE "%'.$network[$i].'%"';
    if( $i != count($network) - 1 )
        $networkqur .= ' OR ';
    

所以 $networkqur 变成了:

$networkqur = "networks LIKE "%Programming%" OR 
               networks LIKE "%Movies%" OR 
               networks LIKE "%Hollywood%";

有效的查询变成了:

$query = "SELECT * FROM posts
          WHERE ( isActive = 1 AND 
                  isDeleted = 0 AND 
                  onid = '0' AND 
                  question = 0 AND 
                   ( networks LIKE "%Programming%" OR 
                     networks LIKE "%Movies%" OR 
                     networks LIKE "%Hollywood% ) 
                   ) 
          ORDER BY id DESC
          LIMIT 0,100;

现在我们可以看到,查询中可以有 150 个 OR 条件和多个 AND 条件,最后是排序。 是否可以替换此特定查询或任何其他更快的方法来执行它?

【问题讨论】:

您需要将networks 拆分到自己的表中并开始使用JOINs 和IN ^ 但是你不认为闯入其他表会增加复杂性和时间吗? 我认为没有更快的解决方案。您可以使用正则表达式,但我认为它甚至会慢一些(但在这种情况下更容易编写)。 您正在使用LIKE '%...%' 您几乎无法做任何事情来加速这些查询——它们不能使用索引。您应该改用全文搜索,至少可以对其进行索引。 这是另一个“我正在打破First Normal Form,现在它让我的生活变得悲惨。我如何让它更快/更容易/更简单?”问题。与往常一样,答案是不要破坏第一范式 【参考方案1】:

您在设计或数据库中犯了严重错误。在设计数据库时应该遵循六条数据库规范化规则,而您已经打破了第一个也是最重要的一条——在每列中只存储一条信息。

除了在您的数据库之上实现一个复杂的全文索引系统之外,没有其他方法可以优化您当前的设计。此外,没有办法执行关系完整性(检查是否只存储了允许的 network 值。您不能索引这些值,也不能在 JOIN 中使用它们。此外,您有一个嵌入的字符串问题,其中搜索(例如) “Holly”将匹配“Holly”、“Hollywood”和“Holly Hunter”。

您应该将 networks 列拆分为单独的表名 post_networks,其中包含 post_idnetwork 列。每个帖子和网络组合添加一行,在(post_id, network) 上添加一个主键,在(network, post_id) 上添加一个主键,您将能够更快速、更安全地执行此查询(以及更多)。

【讨论】:

正如我所说,一个用户可以拥有 150 个网络,这意味着在单独的用户网络关系表中,1k 个用户可以有 100k 个字段。你不认为迭代 100k 行会很麻烦吗? 没有理由不正确地创建结构。事实上,我会创建另一个更小的表(150 行)来列出允许的网络,然后将post_networks 中的network 字段作为外键“保护”到较小的查找表中。【参考方案2】:

如果您的术语列表相对固定(即不是用户生成的),那么这里的一种解决方案是构建您自己的索引表,然后对其进行检查。如果您在添加/编辑主要数据时进行了构建索引的接触点,这可以大大提高SELECT 语句的速度。因此,您的索引表将包含每条记录的主键(最好是 PRIMARY KEY),然后是您要查找的内容的引用。然后,您可以将 INDEX 添加到 term 列,并且您的速度应该会显着提高,因为您正在对索引列进行查找。

理想情况下,您永远不应该对未索引的数据进行查找。

【讨论】:

以上是关于如何使这个 mysqli 查询在 PHP 中运行得更快?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHP 函数中正确使用 MySQL 查询? [关闭]

如何转义 php mysqli 查询? [复制]

如何在 mysqli 查询中使用 while 循环

登录php和mysqli

如何在遍历使用 mysqli_use_result 返回的行时执行 mysqli 查询? (PHP)

在 PHP 中,为啥 mysqli_num_rows 不为返回行数为 0 的查询返回整数?