Разве подготовленные заявления не должны быть намного быстрее? - PullRequest
7 голосов
/ 13 апреля 2010
$s = explode (" ", microtime());
$s = $s[0]+$s[1];
$con = mysqli_connect ('localhost', 'test', 'pass', 'db') or die('Err');

for ($i=0; $i<1000; $i++) {

  $stmt = $con -> prepare( " SELECT MAX(id) AS max_id , MIN(id) AS min_id FROM tb ");
  $stmt -> execute();
  $stmt->bind_result($M,$m);
  $stmt->free_result();
  $rand = mt_rand( $m , $M ).'<br/>';

  $res = $con -> prepare( " SELECT * FROM tb WHERE id >= ? LIMIT 0,1 ");
  $res -> bind_param("s", $rand);
  $res -> execute();
  $res->free_result();
}

$e = explode (" ", microtime());
$e = $e[0]+$e[1];
echo  number_format($e-$s, 4, '.', '');

// and:

$link = mysql_connect ("localhost", "test", "pass") or die ();
mysql_select_db ("db") or die ("Unable to select database".mysql_error());

for ($i=0; $i<1000; $i++) {
  $range_result = mysql_query( " SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM tb ");
  $range_row = mysql_fetch_object( $range_result ); 
  $random = mt_rand( $range_row->min_id , $range_row->max_id );
  $result = mysql_query( " SELECT * FROM tb WHERE id >= $random LIMIT 0,1 ");
}

заранее подготовленные операторы гораздо безопаснее, но также и везде, где говорится, что они намного быстрее, НО в моем тесте на приведенном выше коде у меня есть: - 2,45 с для подготовленных операторов - 5,05 с для второго примера

Как вы думаете, что я делаю не так?Должен ли я использовать второе решение, или я должен попытаться оптимизировать подготовительный STMT?

Ответы [ 4 ]

23 голосов
/ 13 апреля 2010

То, что вы делаете неправильно, заключается в том, что вы готовите утверждение тысячу раз и запускаете каждое подготовленное утверждение только один раз. Вы должны подготовить его один раз и запустить его тысячу раз.

4 голосов
/ 13 апреля 2010

Нет смысла готовить оператор внутри цикла для одного выполнения. Вы просто добавляете накладные расходы. Используйте подготовленные операторы для запросов, которые вы выполняете неоднократно, обычно с разными параметрами.

2 голосов
/ 13 апреля 2010

@ серебристый -

Основы циклов 101 (или простое кодирование 101): уберите код, инвариантный к циклам, из циклов. Зачем вам готовить оператор в цикле, когда он не принимает параметров, которые зависят от самого цикла?

Конечно, гонады будут сосать, если вы будете использовать подготовленные операторы, если будете готовить их с каждой итерацией цикла. Сверхнормативная нагрузка, которую вы наблюдаете, заключается в том, что изначально готовится оператор, а не в его выполнении.

Повторите код и повторите попытку:

$stmt = $con -> prepare( " SELECT MAX(id) AS max_id , MIN(id) AS min_id FROM tb ");
$res = $con -> prepare( " SELECT * FROM tb WHERE id >= ? LIMIT 0,1 ");

for ($i=0; $i<1000; $i++) {

  $stmt -> execute();
  $stmt->bind_result($M,$m);
  $stmt->free_result();
  $rand = mt_rand( $m , $M ).'<br/>';

  $res -> bind_param("s", $rand);
  $res -> execute();
  $res->free_result();
}


Предупреждение здесь , однако, заключается в том, что разница между подготовленным оператором и неподготовленным становится незначительной, так как время вычисления для выполнения запроса и выборки данных становится большой.

Просто чтобы вытащить несколько вымышленных чисел из моего @@@ ради иллюстрации:

Скажем, что сам запрос и выборка данных занимают 0,01 с (назовите это A). Также представьте, что построение и выполнение кода за подготовленным оператором занимает 0,01 с (X), а для неподготовленного запроса - 0,05 с или 5 * 0,01 с (Y = 5 * X). Соотношение между подготовленным и неподготовленным кодом будет:

(A + Y)/(A + X) = 0.06sec/0.02sec = 3 -> unprepared execution is three times slower

И давайте предположим, что для другого запроса время выборки (из-за объема данных или пропускной способности сети) составляет 10 сек (1000 * 0,01 сек). Тогда соотношение меняется

(A + Y)/(A + X) = 10.05sec/10.01sec ~=~ 1.004 

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

1 голос
/ 13 апреля 2010

В дополнение к ответам выше ...

Я вижу, что вы используете MySQL, и ниже приведена ссылка на подготовленные операторы: http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

Отрывок оттуда:

Увеличение производительности в подготовленных высказываниях может быть обусловлено несколькими различными особенностями. Во-первых, необходимо анализировать запрос только один раз. Когда вы изначально готовите оператор, MySQL проанализирует оператор, чтобы проверить синтаксис и настроить запрос для запуска. Тогда, если вы выполняете запрос много раз, он больше не будет иметь таких издержек. Этот предварительный анализ может привести к увеличению скорости, если вам нужно многократно выполнять один и тот же запрос

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...