PHP PDO: re-hazırlığa nasıl bir açıklama performansını etkileyebilir

5 Cevap php

Ben bir yarı-basit bir veritabanı sarıcı sınıfı yazma ve automagically işletecek getirilirken yöntemi var istiyorum değilim: o etrafında sadece ilk kez, her biri farklı deyimi hazırlamak gerekir ve sadece bağlama ve arda çağrılarda sorgu yürütmek .

Ben ana soru sanırım: How does re-preparing the same MySql statement work, will PDO magically recognize the statement (so I don't have to) and cease the operation?

Eşsiz anahtarın altında - not, ben her farklı sorgu için benzersiz bir anahtar oluşturarak bunu ve veritabanı nesnesine özel bir dizi hazırlanmış deyimleri tutmak ulaşmak planlıyorum eğer. (Ben beğendim hiçbiri) aşağıdaki yollardan biri dizi anahtarı elde planlıyorum. Tercih sırası içinde:

  • yöntemi çağrılırken programcı extra, hep aynı parametre geçmek var - satırlar boyunca bir şey basename(__FILE__, ".php") . __LINE__ (bu yöntem bizim yöntem, bir döngü içinde denir yalnızca çalışacak - durumda olan çoğu zaman bu işlevi tabi)
  • programcı ekstra bir parametre olarak (büyük olasılıkla önceden oluşturulan) tamamen rasgele bir dize geçmek var
  • sorgu veya benzer bir şey karmasını alıyorsanız - anahtarı oluşturmak için geçirilen sorguyu kendisi kullanabilir
  • debug_backtrace arayarak ilk kurşunun (yukarıda) gibi aynı elde

Herkes benzer deneyime sahiptir? Ben çalışıyorum sistem does optimizasyonu (oldukça büyük ve hafta büyüyen bulunuyor) biraz dikkat hak olmasına rağmen, belki de ben hiçbir endişe yaşıyorum ve ben ne yapıyor hiçbir performans yararı yoktur yapıyor?

5 Cevap

Tamam, ben sadece sorgu dizesi kendisini kullanarak başka önbellek için sorguları anahtarlama yöntemleri dayak oldum yana, ben naif bir kriter yaptık. Aşağıdaki ilk md5 hash oluşturma vs düz sorgu dizesi kullanarak karşılaştırır:

$ php -v
$ PHP 5.3.0-3 with Suhosin-Patch (cli) (built: Aug 26 2009 08:01:52)
$ ...
$ php benchmark.php
$ PHP hashing: 0.19465494155884 [microtime]
$ MD5 hashing: 0.57781004905701 [microtime]
$ 799994

Kodu:

<?php
error_reporting(E_ALL);

$queries = array("SELECT",
                 "INSERT",
                 "UPDATE",
                 "DELETE",
                 );
$query_length = 256;
$num_queries  = 256;
$iter = 10000;

for ($i = 0; $i < $num_queries; $i++) {
    $q = implode('',
           array_map("chr",
             array_map("rand",
                       array_fill(0, $query_length, ord("a")),
                       array_fill(0, $query_length, ord("z")))));
    $queries[] = $q;
}

echo count($queries), "\n";

$cache = array();
$side_effect1 = 0;
$t = microtime(true);
for ($i = 0; $i < $iter; $i++) {
    foreach ($queries as $q) {
        if (!isset($cache[$q])) {
            $cache[$q] = $q;
        }
        else {
            $side_effect1++;
        }
    }
}
echo microtime(true) - $t, "\n";

$cache = array();
$side_effect2 = 0;
$t = microtime(true);
for ($i = 0; $i < $iter; $i++) {
    foreach ($queries as $q) {
        $md5 = md5($q);
        if (!isset($cache[$md5])) {
            $cache[$md5] = $q;
        }
        else {
            $side_effect2++;
        }
    }
}
echo microtime(true) - $t, "\n";

echo $side_effect1 + $side_effect2, "\n";

(Çoğu DBMS gibi) MySQL hazırlanan tablolar için yürütme planları önbelleğe, böylece kullanıcı bir için bir plan oluşturur eğer olacaktır:

SELECT * FROM some_table WHERE a_col=:v1 AND b_col=:v2

(V1 ve v2 bağlama vars nerede) sonra DBMS aradeğerlenmesi değerlerini gönderir, sonra kullanıcı B aynı sorguyu gönderir (ama enterpolasyon için farklı değerlerle) DBMS planını yeniden zorunda değildir. yani onun eşleşen planı bulur DBMS - değil PDO.

Ancak bu değişmez değerleri ile bir sorgu için bir tek yuvarlak gezi aksine veritabanı üzerinde her işlemi (vars bağlama sunmak için sorguyu sunmak için 1, ikinci), en az 2 tur gezileri gerektirir anlamına gelir, o zaman bu ek ağ maliyetlerinden tanıttı . Çözümleyecek (ve muhafaza) sorgu / Plan önbelleği dahil küçük bir maliyeti de vardır.

Anahtar soru bu maliyet ilk etapta planı oluşturma maliyeti daha büyük olup olmadığıdır.

(Benim) kesinlikle Oracle ile hazırlanmış deyimleri kullanarak bir performans yararı var gibi görünüyor olsa da, ben aynı MySQL için doğru olduğunu ikna değilim - ancak bir çok şey veritabanı strucutre ve sorgu karmaşıklığına bağlıdır (ya da daha spesifik olarak kaç farklı seçenek iyileştirici sorgu çözmek için bulabilirsiniz).

(Ipucu 0'a yavaş sorgu eşiğini ayarlamak ve geri günlükleri yazılı sorguları için anonim gösterimleri içine değişmez değerleri dönüştürmek için bazı kod yazmak isteyebilirsiniz) kendiniz ölçme deneyin

C.

Preparing SQL Statements with PDO : Bu soruya bakın - İnan bana, ben önce ve performans kazancı very farkedilir hazırlanan tabloların bir önbellek oluşturduktan sonra yaptık.

Bir bu önbelleğe hazırlanıp, sonra geldi kod oldu:

function DB($query)
{
    static $db = null;
    static $result = array();

    if (is_null($db) === true)
    {
        $db = new PDO('sqlite:' . $query, null, null, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
    }

    else if (is_a($db, 'PDO') === true)
    {
        $hash = md5($query);

        if (empty($result[$hash]) === true)
        {
            $result[$hash] = $db->prepare($query);
        }

        if (is_a($result[$hash], 'PDOStatement') === true)
        {
            if ($result[$hash]->execute(array_slice(func_get_args(), 1)) === true)
            {
                if (stripos($query, 'INSERT') === 0)
                {
                    return $db->lastInsertId();
                }

                else if (stripos($query, 'SELECT') === 0)
                {
                    return $result[$hash]->fetchAll(PDO::FETCH_ASSOC);
                }

                else if ((stripos($query, 'UPDATE') === 0) || (stripos($query, 'DELETE') === 0))
                {
                    return $result[$hash]->rowCount();
                }

                else if (stripos($query, 'REPLACE') === 0)
                {
                }

                return true;
            }
        }

        return false;
    }
}

Ben sorgularda çarpışmalar hakkında endişelenmenize gerek yok çünkü, ben md5() yerine sha1() ile sona erdi ettik.

Aynı sorgu ise o bilmiyor bu nedenle kendisi tarafından sorgu analiz yok gibi benim bilgi için PDO zaten hazır deyimleri yeniden değil.

Eğer hazırlanan sorguları önbellek oluşturmak istiyorsanız, basit yolu imho md5-hash sorgu dizesi olabilir ve bir arama tablosu oluşturmak istiyorum.

OTOH: Eğer (dakikada) kaç sorguları yürütme? Yüz daha az bir kaç sonra sadece kod karmaşık olursa, performans artışı küçük olacaktır.

Sonunda aynı MD5 hash neden iki sorguları alabilir bir anahtar olarak bir MD5 hash kullanarak. Olasılık yüksek değil, ama olabilirdi. Bunu yapmayın. MD5 gibi Lossful özetleme algoritmaları sadece iki nesneleri yüksek kesinlik ile farklı olmadığını söylemek için bir yol olarak ment, ama bir şey belirlenmesi güvenli bir araç değildir edilir.