$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?
Что вы делаете неправильно, так это то, что вы готовите инструкцию тысячу раз и запускаете каждую подготовленную инструкцию только один раз. Вы должны подготовить его один раз и запустить тысячу раз.
@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
. Они почти неразличимы. Я пытаюсь сказать, что да, подготовленные операторы работают быстрее (и вы должны их использовать), НО тест, который вы выполняете, не обязательно является хорошим способом выяснить это или измерить их ценность.Вы должны принять во внимание другие факторы, чтобы действительно измерить производительность, которую вы из них добиваетесь.
Нет никакой пользы от подготовки оператора внутри цикла для однократного выполнения. Вы просто добавляете накладные расходы. Используйте подготовленные операторы для запросов, которые вы выполняете повторно, обычно с разными параметрами.
В дополнение к приведенным выше ответам ...
Я вижу, что вы используете MySQL, и ниже находится ссылка на подготовленные операторы: { {1}} http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
Выдержка оттуда:
Повышение производительности подготовленных операторов может произойти от нескольких различных функций. Во-первых, необходимо проанализировать запрос только один раз. При первоначальной подготовке оператора MySQL проанализирует его, чтобы проверить синтаксис и настроить запрос для выполнения. Тогда, если вы выполните запрос много раз, у него больше не будет этих накладных расходов. Этот предварительный анализ может привести к увеличению скорости, если вам нужно выполнить один и тот же запрос много раз