Php MySQL和PDO,加快查询速度并从MySQL函数(例程)获取结果/输出?
获取值: 我已经从MySQL数据库中获得了levenshtein_ratio函数。我以以下方式运行它:Php MySQL和PDO,加快查询速度并从MySQL函数(例程)获取结果/输出?,php,mysql,pdo,mysql-routines,Php,Mysql,Pdo,Mysql Routines,获取值: 我已经从MySQL数据库中获得了levenshtein_ratio函数。我以以下方式运行它: $stmt = $db->prepare("SELECT r_id, val FROM table WHERE levenshtein_ratio(:input, someval) > 70"); $stmt->execute(array('input' => $input)); $result = $stmt->fetchAll();
$stmt = $db->prepare("SELECT r_id, val FROM table WHERE levenshtein_ratio(:input, someval) > 70");
$stmt->execute(array('input' => $input));
$result = $stmt->fetchAll();
if(count($result)) {
foreach($result as $row) {
$out .= $row['r_id'] . ', ' . $row['val'];
}
}
这是一种享受,完全符合预期。但是我想知道,有没有一种很好的方法也可以得到levenshtein\u ratio()
计算的值
我试过:
$stmt = $db->prepare("SELECT levenshtein_ratio(:input, someval), r_id, val FROM table WHERE levenshtein_ratio(:input, someval) > 70");
$stmt->execute(array('input' => $input));
$result = $stmt->fetchAll();
if(count($result)) {
foreach($result as $row) {
$out .= $row['r_id'] . ', ' . $row['val'] . ', ' . $row[0];
}
}
它在技术上是可行的(我从$row[0]
中获取百分比),但是查询有点难看,我无法使用正确的键来获取值,就像我可以为其他两个项目获取值一样
有没有办法找到一个好的参考资料
我试过:
$stmt = $db->prepare("SELECT r_id, val SET output=levenshtein_ratio(:input, someval) FROM table WHERE levenshtein_ratio(:input, someval) > 70");
根据我在网上找到的东西建模,但它不起作用,最终破坏了整个查询
加快速度:
我正在对一个值数组运行此查询:
foreach($parent as $input){
$stmt = ...
$stmt->execute...
$result = $stmt->fetchAll();
... etc
}
但它最终会非常缓慢。对于一个只有14个输入的数组和一个大约350行的DB,速度大约为20秒,预计很快将达到10000。我知道将查询放在循环中是一件很棘手的事情,但我不知道还有什么办法可以绕过它
编辑1
当我使用
$stmt = $db->prepare("SELECT r_id, val SET output=levenshtein_ratio(:input, someval) FROM table WHERE levenshtein_ratio(:input, someval) > 70");
如果我只计算过一次,那肯定要花两倍的时间?类似于拥有
$i在for循环中?要清除列名,可以使用“as”重命名函数的列。同时,您可以通过在where子句中使用该列名来加快速度,从而使函数只执行一次
$stmt = $db->prepare("SELECT r_id, levenshtein_ratio(:input, someval) AS val FROM table HAVING val > 70");
如果它仍然太慢,你可以考虑一个C库,比如
doh-如spencer7593所述,忘记将“where”切换为“having”。我假设'someval'是对表中某列的不合格引用。虽然您可以理解,如果不查看表定义,其他阅读SQL语句的人就无法判断。作为对未来读者的帮助,考虑将列引用限定为表的名称,或者(最好)是在语句中分配给表的短别名。
SELECT t.r_id
, t.val
FROM `table` t
WHERE levenshtein_ratio(:input, t.someval) > 70
必须为表中的每一行计算WHERE子句中的函数。没有办法让MySQL在此基础上构建索引。因此,无法让MySQL执行索引范围扫描操作
可以让MySQL为查询使用索引,例如,如果查询有一个orderbyt.val
子句,或者如果有一个“覆盖索引”可用
但这并不能回避需要为每一行计算函数的问题。(如果查询具有排除行的其他谓词,则不一定需要为排除的行计算函数。)
如果函数被声明为确定性的,那么将表达式添加到选择列表中应该不会太昂贵。对具有相同参数的确定性函数的第二次调用可以重用为上一次执行返回的值。(声明函数确定性本质上意味着,当给定相同的参数值时,函数保证返回相同的结果。重复调用将返回相同的值。也就是说,返回值仅取决于参数值,而不依赖于任何其他值
SELECT t.r_id
, t.val
, levenshtein_ratio(:input, t.someval) AS lev_ratio
FROM `table` t
WHERE levenshtein_ratio(:input2, t.someval) > 70
(注意:我在第二次引用中使用了一个不同的绑定占位符名称,因为PDO不会像我们预期的那样处理“重复”的绑定占位符名称。(这可能在PDO的最新版本中得到了更正。第一个“修复”对于这个问题,对文档进行了更新,指出绑定占位符名称在语句中只应出现一次,如果需要对同一个值进行两次引用,请使用两个不同的占位符名称,并将同一个值绑定到这两个值。)
如果不想重复表达式,可以将条件从WHERE子句移动到HAVING,并通过指定给列的别名引用SELECT列表中的表达式
SELECT t.r_id
, t.val
, levenshtein_ratio(:input, t.someval) AS lev_ratio
FROM `table` t
HAVING lev_ratio > 70
WHERE和HAVING的最大区别在于WHERE子句中的谓词是在访问行时计算的,HAVING子句是在访问行之后计算的。(这简要解释了为什么HAVING子句可以通过别名引用SELECT列表中的列,但WHERE子句不能这样做。)
如果这是一个大表,并且排除了大量行,那么使用HAVING子句可能会有显著的性能差异。可能会创建一个更大的中间集
要获取用于查询的“索引”,覆盖索引是我看到的唯一选项
ON `table` (r_id, val, someval)
这样,MySQL就可以满足索引中的查询,而不需要在基础表中查找页面。查询所需的所有列值都可以从索引中获得
跟进
要创建索引,我们需要创建一列,例如
lev_ratio_foo FLOAT
并使用函数的结果预填充
UPDATE `table` t
SET t.lev_ratio_foo = levenshtein_ratio('foo', t.someval)
;
然后我们可以创建一个索引,例如
... ON `table` (lev_ratio_foo, val, r_id)
然后重新编写查询
SELECT t.r_id
, t.val
, t.lev_ratio_foo
FROM `table` t
WHERE t.lev_ratio_foo > 70
通过该查询,MySQL可以对以lev_ratio_foo作为前导列的索引使用索引范围扫描操作
当向表中添加新行或修改someval列的值时,我们可能希望添加BEFORE INSERT和BEFORE UPDATE触发器来维护该值
该模式可以扩展,可以为“foo”以外的值添加其他列。例如,“bar”
UPDATE `table` t
SET t.lev_ratio_bar = levenshtein_ratio('bar', t.someval)
显然,这种方法对于广泛的输入值来说是不可伸缩的。不应该$stmt->execute(数组('input'=>$input));
应该$stmt->execute(数组(':input'=>$input))
?@thecodese可能吧?可能吧。我是mysqli的人,这是我第一次接触PDO。无论哪种方式都有效。@thecodese检查出来。没有说这就是结局,他可能是错的,但我现在的工作方式是这样的。我一直在拔头发,因为不是这样