Мудрое сопоставление строк с точки зрения производительности

StackOverflow https://stackoverflow.com/questions/2010867

Вопрос

У меня есть общая функция запроса к БД, которая выполняет следующие проверки каждый раз, когда выдается запрос 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 модификатор шаблона во втором варианте тоже вносит некоторую путаницу в голову, из мануала:

Когда шаблон будет использоваться несколько раз, стоит потратить больше времени на анализ его, чтобы ускорить время, необходимое для сопоставления.Если этот модификатор установлен, то этот дополнительный анализ выполняется.В настоящее время изучение шаблона полезно только для некированных моделей, которые не имеют ни одного фиксированного начального символа.

В этом случае скорость не имеет решающего значения (иначе я бы не использовал эту общую функцию запроса), но мне все равно хотелось бы, чтобы она работала как можно быстрее, сохраняя при этом ее простоту.

Какой из вышеперечисленных вариантов мне выбрать?


РЕДАКТИРОВАТЬ: у меня есть запустите простой тест и до сих пор не могу решить, какой метод работает лучше.

Вот результаты для 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

Я использовал следующие регулярные выражения, поскольку они кажутся более быстрыми (для совпадающего и несовпадающего текста):

  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)

Другие советы

Я бы, наверное, не стал использовать ни один из них.Я не могу быть уверен без сравнительного анализа, но я думаю, что substr() будет более быстрым вариантом, чем stripos, поскольку он не будет сканировать всю строку.Предполагая UPDATE и DELETE всегда возникают в начале запроса, и, что еще лучше, они оба имеют длину ровно 6 символов, поэтому вы можете сделать это за один substr():

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

Если вам нужно, вы можете добавить trim() там для любых пробелов с префиксом, но, вероятно, это не обязательно.

Если вы выполняете вложенные или подзапросы с помощью UPDATE и DELETE, то, очевидно, описанный выше метод не будет работать, и я бы выбрал stripos() маршрут.Если вы сможете отказаться от регулярных выражений в пользу обычных строковых функций, это будет быстрее и проще.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top