我有一个循环遍历满足某个条件的表的所有行的方法,然后检查该行中的一个列是否出现在文本中。方法如下:
public function isRecipeType($ingredients, $type)
{
$rows = $this->fetchAll($this->select()->where("type = ?", $type));
foreach($rows as $row)
{
if((strpos($ingredients, $row->name)) !== false)
{
return true;
}
}
}
但这需要永远。如何加快速度(不从表中删除行)?
答案 0 :(得分:3)
您尝试解决的问题可以表示为“是否存在任何行,类型= X,其名称包含文本Y?”
这是数据库可以回答的问题,无需在PHP中编写循环。使用数据库更快,数据库可以访问有关调优的更多信息。基本上将匹配该类型的表的整个子集从数据库(可能通过网络)下载到PHP处理器以回答查询是低效的。让DB为您完成工作。它也更容易阅读,因为SQL是一种声明性语言,而不是PHP解决方案必不可少。
public function isRecipeType($ingredients, $type)
{
$sql = "SELECT COUNT(*) AS c ".
"FROM table ".
"WHERE type = ? ".
" AND ? LIKE CONCAT('%', name, '%')";
$rows = execute($sql, $type, $ingredients);
$row = $rows[0];
return $row["c"] > 0;
}
这使用MySQL语法,如果您使用另一个数据库,则用
替换SQL的最后一行 " AND ? LIKE '%' || name || '%'";
我在你的代码中发明了一个execute
方法,我不知道你正在使用什么数据库访问层,但毫无疑问你可以访问类似的东西。
如另一个答案所示,请确保type
列上有索引。然后,此语句的执行计划将是:查找具有匹配类型的所有行(使用索引),然后浏览数据并应用LIKE。
除非超过例如10%的行与类型列匹配,然后对所有数据的顺序读取(即不使用索引)将比使用索引识别行然后随机访问读取它们更快。但是数据库会知道是否是这种情况,创建索引并没有坏处,然后数据库可以根据这个标准使用它。
答案 1 :(得分:2)
首先,您是否在type
列上定义了索引?由于这是您搜索中唯一的条件,因此您希望它是一个有效的条件。
答案 2 :(得分:2)
你不能用SQL做一切吗?
已更正 - 未经测试 - 例如:
"... WHERE `type`=? AND FIND_IN_SET(name, `$ingredients`) > 0 LIMIT 1"
// return TRUE if a row is found
要使FIND_IN_SET
生效,必须用逗号分隔值,这样您就可能需要转换$ingredients
变量。