Php 当结果需要多个联接时,优化搜索给定表

Php 当结果需要多个联接时,优化搜索给定表,php,mysql,optimization,mariadb,Php,Mysql,Optimization,Mariadb,我正在开发一个应用程序,它是一个大型的化学物质数据库(约250000个,但不断增加)和相关数据。我正在寻找优化搜索方式的方法 该应用程序在PHP7.0.27、MariaDB 5.5.56和Apache2.4.6下运行 该应用程序允许通过化学名称和各种化学代码(如EC编号和CAS编号)进行搜索。模式是这样的,即有单独的表来保存数据,以及哪些代码适用于哪些化学品的关系 这些表位于数据库中: 物质-每种化学物质的唯一ID和名称 ecs-EC编号列表 ecs\u物质-哪个EC编号适用于哪个物质 cas

我正在开发一个应用程序,它是一个大型的化学物质数据库(约250000个,但不断增加)和相关数据。我正在寻找优化搜索方式的方法

该应用程序在PHP7.0.27、MariaDB 5.5.56和Apache2.4.6下运行

该应用程序允许通过化学名称和各种化学代码(如EC编号和CAS编号)进行搜索。模式是这样的,即有单独的表来保存数据,以及哪些代码适用于哪些化学品的关系

这些表位于数据库中:

  • 物质
    -每种化学物质的唯一ID和
    名称
  • ecs
    -EC编号列表
  • ecs\u物质
    -哪个EC编号适用于哪个
    物质
  • cas
    -cas编号列表
  • cas\U物质
    -哪个cas编号适用于哪个
    物质
注意:除了上面的表之外,还有其他类似逻辑适用的表,但现在我想在这个示例中重点介绍这些表

一种物质可能有多个EC/CAS编号,而一小部分没有这些编号——即,这不是一个简单的1:1关系

该应用程序具有物质名称(
substances.name
)、EC编号(
ecs.value
)CAS编号(
CAS.value
)的搜索字段。它们可以单独使用,也可以相互结合使用。例如:按名称查找物质,或按名称和CAS号查找物质

我认为搜索任何给定值的“最快”方法是在所需的特定表上使用
LIKE
条件。因此,如果我想查找名称中含有“酸”的物质:

SELECT id FROM substances WHERE name LIKE '%acids%' LIMIT 0,250
然而,申请书给出的结果显示在一个表格中,该表格包括物质名称、CAS编号、EC编号的标题。它还允许在列上对结果进行排序(例如,按物质名称、CAS、EC等排序)。这需要
JOIN
条件

我是这样做的:

$sql = 'SELECT 
DISTINCT(substances.`id`),            
substances.`name`,
"" AS cas_number, 
"" AS ec_number
FROM
 substances ';
    
// Search - EC Number, or if trying to order by EC column (JOIN has to occur to make that possible)
if ( (isset($search['ecNumber'])) || (isset($order['column']) && ($order['column'] == 'ec_number')) ) {
    $sql .= ' LEFT JOIN ecs_substances ON substances.id = ecs_substances.substance_id LEFT JOIN ecs ON ecs_substances.ec_id = ecs.id ';
}

// Search - CAS Number, or if trying to order by CAS column (JOIN has to occur to make that possible)
if ( (isset($search['casNumber'])) || (isset($order['column']) && ($order['column'] == 'cas_number')) ) {
$sql .= ' LEFT JOIN cas_substances ON cas_substances.substance_id = substances.id LEFT JOIN cas ON cas_substances.cas_id = cas.id ';
}
问题是,由于所有的
JOIN
s都在发生,因此会减慢获得结果的速度

基准测试:我发布的第一个查询只在1个表上使用了
LIKE
条件,将在140ms内执行,而对于第二个代码块中的所有
JOIN
语句,相同的搜索条件需要506ms

我想知道是否有办法对此进行优化,以减少向用户展示结果所需的时间

值得一提的是,结果显示在中,PHP正在生成结果的JSON提要。
限制0250
是最终用户可以通过设置每页的结果来覆盖的,但我很高兴将它们限制在每页不超过500个

我调查过的一些事情是:

  • 缓存JSON。不太喜欢这个,因为数据是定期更新的。提供的数据必须始终是数据库中的数据,而不是某个缓存副本

  • 在第一个代码示例中搜索所需的表。使用ajax更新其他列。这将“显示”为用户搜索的列提供即时结果,然后快速填充DataTable所需的其他列。这似乎是非常棘手的事情,我不知道这是否真的是个好主意


    • 考虑到您想要做的事情,我认为半秒钟的响应时间非常好。您必须完成所有必要的数据库优化吗?(数据库类型、索引等)

      您可以探索以下几点:

    • 准备所有可能的搜索,并将其存储在数据库中以便快速访问。这听起来可能很愚蠢,但这就是我经常实现快速搜索的方式。我很难判断用你的数据做这件事的最佳方式是什么。您可以首先在substances表中添加一个文本列,并在其中存储有关该物质的所有信息:名称和所有EC/CAS编号。使用类似“|”的字符或搜索中未使用的任何其他字符分隔项目。我称之为“搜索”栏。或者,您可以创建一个新表,仅用于搜索其中的列以及物质的id。现在,您可以为所有三种类型的数据创建一个搜索输入字段,并仅在一列中搜索。那对你有用吗?会更快吗?可能吧,但我不能保证。我不知道,但这很容易尝试。有一个缺点:您必须随着数据库中的每次更改更新该列

    • 使用合适的搜索引擎。mariadb可以使用几个。首先:它基本上做了一些比我在第1点中描述的要高级得多的事情:准备一个包含优化搜索数据的数据库


    • 不过,半秒钟的响应时间是我可以接受的。

      考虑到你想做的事情,我认为半秒钟的响应时间是相当不错的。您必须完成所有必要的数据库优化吗?(数据库类型、索引等)

      您可以探索以下几点:

    • 准备所有可能的搜索,并将其存储在数据库中以便快速访问。这听起来可能很愚蠢,但这就是我经常实现快速搜索的方式。我很难判断用你的数据做这件事的最佳方式是什么。您可以首先在substances表中添加一个文本列,并在其中存储有关该物质的所有信息:名称和所有EC/CAS编号。使用类似“|”的字符或搜索中未使用的任何其他字符分隔项目。我称之为“搜索”栏。或者,您可以创建一个新表,仅用于搜索其中的列以及物质的id。现在,您可以创建一个搜索输入字段