Разве подготовленные операторы не должны быть намного быстрее?

$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 ");
}

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

Что Вы думаете, что я делаю неправильно? Я должен использовать второе решение, или я должен попытаться оптимизировать подготовительную школу stmt?

7
задан Zan Lynx 13 April 2010 в 00:33
поделиться

4 ответа

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

23
ответ дан 6 December 2019 в 06:02
поделиться

@silversy -

Основы цикла 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 

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

2
ответ дан 6 December 2019 в 06:02
поделиться

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

4
ответ дан 6 December 2019 в 06:02
поделиться

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

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

Выдержка оттуда:

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

1
ответ дан 6 December 2019 в 06:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: