2010-04-13 3 views
7
$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에 대한 예 :준비된 문장이 훨씬 빨라지면 안됩니까?

내가 뭘 잘못하고 있다고 생각하니? 두 번째 솔루션을 사용해야합니까, 아니면 prep stmt를 최적화해야합니까?

+6

2.45 *는 5.05보다 빠름? –

+2

코드를 읽을 수 있도록 포맷하십시오. –

+0

OMG .. 만약 당신이 이렇게 쓰면 사람들은 아무 것도 이해할 수 없습니다. 제대로 포맷하십시오. –

답변

23

잘못하고있는 것은 계산서를 수천 번 준비하고 준비된 각 명령문을 한 번만 실행한다는 것입니다. 한 번 준비하고 천 번 실행해야합니다. http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

발췌 거기에서 :

위의 답변에 추가

+2

더 명확히하려면 한 번 준비한 다음 수천 번 바인딩하고 실행해야합니다. – MJB

+1

사람들이 루프에서 불변량의 개념을 이해하지 못하면 어떻게됩니까? -/ –

+0

나는 루프에 대해 준비된 명령문을 모두 넣었습니다. 이제는 2.33 초이고 ack2에 2.45를 가졌습니다. 정상입니까? 그것은 단지 3 % 향상입니다. – silversky

4

루프 내에서 단일 실행을 준비하는 것은 이점이 없습니다. 오버 헤드를 추가하는 것뿐입니다. 대개 다른 매개 변수를 사용하여 반복적으로 실행하는 쿼리에는 준비된 문을 사용하십시오.

+0

예 실제로 준비된 stmt를 루프 안에 넣는 것은 큰 실수였습니다.하지만 둘 다 준비하면 루프는 결과가 2.39 초 밖에되지 않습니다. 3 % 속도 향상 더 많지 않아야합니까? – silversky

+1

일 필요는 없습니다. 주요 절약은 쿼리에 대한 쿼리 계획을 작성하는 것입니다. 사소한 SQL 문이라면 저장할 것이별로 없습니다. 정말로 컴파일 된 것이 없으므로 실제로 CPU 사이클이 없기 때문에 쿼리가 디스크를 때리면 (즉 데이터가 캐싱되지 않음) 신속하게 모든 사이클을 절약 할 수 있습니다 - 디스크 액세스가 훨씬 느립니다 CPU주기보다. – dkretz

+0

db가 42.000에 그다지 크지는 않지만 훨씬 더 많은 비용 절감을 기대하고있었습니다. 하지만 아마도 당신은 라이트를 가졌을 것입니다. – silversky

1

...

난 당신이 아래에 MySQL을 사용하고 있습니다보고는 거기에서 준비된 문에 같은 링크입니다 준비된 명령문의 성능 향상은 몇 가지 다른 기능에서 비롯 될 수 있습니다. 첫 번째는 쿼리를 한 번만 구문 분석해야하는 경우입니다. 초기에 명령문을 준비 할 때, MySQL은 명령문을 구문 분석하여 구문을 검사하고 실행할 쿼리를 설정합니다. 그런 다음 쿼리를 여러 번 실행하면 더 이상 오버 헤드가 발생하지 않습니다. 루프 밖으로 이동 루프 불변 코드 :

루프 기본 101 (또는 일반 코딩 101) - 같은 쿼리를 여러 번

+1

제가 말했듯이, 루프 안에 넣는 것이 큰 실수였습니다.하지만 $ con -> prepare()를 넣은 후에는 3-5 %의 속도 향상 만 얻었습니다. 나는 훨씬 더, 적어도 20-30 %의 속도 증가를 기대했다. – silversky

+0

속도가 증가 할 때 왜 임의의 %를 기대 하시겠습니까? 성능 향상과 측정은 그렇게 작동하지 않습니다. 이것은 가져 오는 데이터 크기와 처리량에 완전히 달려 있습니다. (더 자세한 설명은 제 응답을 참조하십시오.) –

+0

추가하려면 장기적으로 응용 프로그램의 상태와 성능에 대해 준비된 문 사용에 대한 이득이 있어야한다고 생각합니다. 파싱하는 동안 생성되는 임시 개체가 덜 생성됩니다. 원시 실행 번호가 아닙니다. 그리고 시간이 지남에 따라 쿼리 (또는 코드 조각)가 언제 어떻게 사용되는지 알려지기 때문에 준비된 모든 명령문을 작성하는 것이 좋습니다. –

2

@silversy를 실행해야하는 경우 사전 분석은 속도 증가로 이어질 수 . 루프 자체에 의존하는 매개 변수를 사용하지 않으면 루프에서 명령문을 준비하는 이유는 무엇입니까?

물론 루프 스테이트먼트를 준비 할 때 준비된 문장을 사용하면 생식선을 빨아 먹을 것입니다. 당신이 관찰 한 오버 헤드는 명령문이 실행되기보다는 준비되는 시점에 있습니다.

다음과 같이 코드를 다시 수행하고 다시 재 시도 :

$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 초를 소요 말 (이것을 호출). 또한 준비된 명령문 뒤에있는 코드의 작성 및 실행에는 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 

과의 또 다른 쿼리에 대한 것을 가정하자 (때문에 데이터 볼륨 또는 네트워크 처리량)을 가져 오는 시간이 10secs (* 0.01 초 1000)입니다. 그런 다음 비율이 변경됩니다.

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

그들은 거의 구별 할 수 없습니다. 제가 말하고자하는 것은 예, 준비된 진술이 더 빠르다는 것입니다 (그렇지만 그것을 사용해야 만합니다). 그러나 당신이 구현하고있는 테스트가 반드시 그 값을 찾아 내거나 가치를 측정하는 좋은 방법은 아닐 수도 있습니다. 자신이 짜내는 성능을 실제로 측정하기 위해서는 다른 요소도 고려해야합니다.

+0

@ uis.espinal, 고마워요. – silversky