【问题标题】:Performance wise String Matching性能明智的字符串匹配
【发布时间】:2011-01-01 22:10:30
【问题描述】:

我有一个通用的数据库查询函数,每次发出 SQL 查询时都会运行以下检查:

  1. if (preg_match('~^(?:UPDATE|DELETE)~i', $query) === 1)
  2. if (preg_match('~^(?:UPDATE|DELETE)~iS', $query) === 1)
  3. if ((stripos($query, 'UPDATE') === 0) || (stripos($query, 'DELETE') === 0))

我知道一个简单的strpos() 调用比调用preg_match() 快得多,但是由于我调用了两次strIpos(),我真的不确定哪一个应该执行得更好.

第二个选项中的S 模式修饰符也给我带来了一些困惑,来自手册:

何时使用模式 几次,值得花 更多的时间来分析它,以便 加快匹配所需的时间。 如果设置了这个修饰符,那么这个 进行额外的分析。在 目前,研究模式很有用 仅适用于非锚定模式 没有一个固定的起点 字符。

在这种情况下,速度并不重要(否则我不会使用这个通用查询函数)但是,我仍然希望让它尽可能快地运行,同时保持它的简单性。

我应该选择以上哪个选项?


编辑:我已经run a simple benchmark,但我仍然无法确定哪种方法效果更好。

这是 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
        )
)

您可以看到结果差异很大,这让我想知道这是否是进行基准测试的正确方法。

【问题讨论】:

  • ....查询需要多长时间才能运行?这看起来像是过早的优化。

标签: php regex string string-matching strpos


【解决方案1】:

我可能不会使用其中任何一个。如果没有基准测试,我无法确定,但我认为substr()stripos 更快,因为它不会扫描整个字符串。假设 UPDATEDELETE 总是出现在查询的开头,更好的是,它们都是 6 个字符长,所以你可以在一个 substr() 中完成:

$queryPrefix = strtoupper(substr($query,0,6));
if ($queryPrefix == 'UPDATE' || $queryPrefix == 'DELETE') {

如果需要,您可以在其中为任何前缀空格添加 trim(),但这可能不是必需的。

如果您使用 UPDATE 和 DELETE 进行嵌套或子查询,那么显然上述方法不起作用,我会使用 stripos() 路由。如果您可以避免使用正则表达式而使用普通字符串函数,它会更快且更简单。

【讨论】:

  • 我也考虑过这一点(不确定substr() + strtoupper() 是否比stripos() 快)但是有一个问题:我无法检查REPLACEEXPLAIN 类型的查询,因为它们都有 7 个字符。
  • 所有这些函数(substr()、trim()、strtoupper())创建一个新字符串(包括内存分配)。如果可能的话,我会避免这种情况。
【解决方案2】:

我使用了以下正则表达式,因为它们似乎更快(在匹配和不匹配的文本上):

  1. if (preg_match('~^(?:INSERT|REPLACE)~i', $query) === 1)
  2. else if (preg_match('~^(?:UPDATE|DELETE)~i', $query) === 1)
  3. else if (preg_match('~^(?:SELECT|EXPLAIN)~i', $query) === 1)

【讨论】:

    猜你喜欢
    • 2021-11-06
    • 1970-01-01
    • 2015-06-18
    • 2011-11-23
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    相关资源
    最近更新 更多