性能明智的字符串匹配
-
18-09-2019 - |
题
我有一个通用的数据库查询函数,每次发出 SQL 查询时都会运行以下检查:
if (preg_match('~^(?:UPDATE|DELETE)~i', $query) === 1)
if (preg_match('~^(?:UPDATE|DELETE)~iS', $query) === 1)
if ((stripos($query, 'UPDATE') === 0) || (stripos($query, 'DELETE') === 0))
我知道一个简单的 strpos()
调用比执行要快得多 preg_match()
, ,但是既然我打电话 strIpos()
两次 我真的不确定哪一个应该表现得更好。
这 S
第二个选项中的模式修饰符也给我带来了一些困惑,来自手册:
当要多次使用模式时,值得花更多的时间来分析它,以加快匹配时间的速度。如果设置了此修饰符,则执行此额外的分析。目前,研究模式仅适用于没有单个固定起始字符的非锚定模式。
在这种情况下,速度并不重要(否则我不会使用这个通用查询函数),但是,我仍然想让它尽可能快地运行,同时保持它的简单性。
我应该选择以上哪个选项?
编辑: 我有 运行一个简单的基准测试 但我仍然无法决定哪种方法效果更好。
以下是结果 10,000 次尝试 (所用总时间,以秒为单位):
Array
(
[match] => Array
(
[stripos] => 0.0965
[preg_match] => 0.2445
[preg_match?] => 0.1227
[preg_match?S] => 0.0863
)
[no-match] => Array
(
[stripos] => 0.1165
[preg_match] => 0.0812
[preg_match?] => 0.0809
[preg_match?S] => 0.0829
)
)
100,000 次尝试:
Array
(
[match] => Array
(
[stripos] => 1.2049
[preg_match] => 1.5079
[preg_match?] => 1.5564
[preg_match?S] => 1.5857
)
[no-match] => Array
(
[stripos] => 1.4833
[preg_match] => 0.8853
[preg_match?] => 0.8645
[preg_match?S] => 0.8986
)
)
1,000,000 次尝试:
Array
(
[match] => Array
(
[stripos] => 9.4555
[preg_match] => 8.7634
[preg_match?] => 9.0834
[preg_match?S] => 9.1629
)
[no-match] => Array
(
[stripos] => 13.4344
[preg_match] => 9.6041
[preg_match?] => 10.5849
[preg_match?S] => 8.8814
)
)
10,000,000 次尝试:
Array
(
[match] => Array
(
[stripos] => 86.3218
[preg_match] => 93.6755
[preg_match?] => 92.0910
[preg_match?S] => 105.4128
)
[no-match] => Array
(
[stripos] => 150.9792
[preg_match] => 111.2088
[preg_match?] => 100.7903
[preg_match?S] => 88.1984
)
)
正如您所看到的结果差异很大,这让我想知道这是否是进行基准测试的正确方法。
解决方案 2
我使用了以下正则表达式,因为它们似乎更快(在匹配和不匹配的文本上):
if (preg_match('~^(?:INSERT|REPLACE)~i', $query) === 1)
else if (preg_match('~^(?:UPDATE|DELETE)~i', $query) === 1)
else if (preg_match('~^(?:SELECT|EXPLAIN)~i', $query) === 1)
其他提示
我可能不会使用其中任何一个。如果没有基准测试,我无法确定,但我认为 substr()
将是一个比 stripos
, ,因为它不会扫描整个字符串。假设 UPDATE
和 DELETE
总是出现在查询的开头,更好的是,它们的长度都是 6 个字符,因此您可以在一个查询中完成它 substr()
:
$queryPrefix = strtoupper(substr($query,0,6));
if ($queryPrefix == 'UPDATE' || $queryPrefix == 'DELETE') {
如果您需要,您可以添加 trim()
那里有任何前缀空白,但这可能不是必需的。
如果您使用 UPDATE 和 DELETE 进行嵌套查询或子查询,那么显然上述方法不起作用,我会选择 stripos()
路线。如果您可以避免使用正则表达式而使用普通字符串函数,那么它会更快且更简单。