Hazırlanan Tablolar Normal sorguları için bir atık mı?

8 Cevap php

Günümüzde, "Hazır deyimler" Herkes bir veritabanına sorgular göndererek tavsiye tek yol gibi görünüyor. Hatta saklı yordamlara için hazırlanmış ifadeler kullanmak tavsiyeler bakın. Ancak, fazladan sorgu yapmak ifadeleri gerektirir hazırlanmış - ve son kısa zaman - onlar INSERT / UPDATE sorgularının hattı için sadece yararlı olduğuna ikna ediyorum.

Birisi bu beni düzeltebilir umuyorum, ama sadece CSS şey "Tablolar kötülük vardır" bütünün bir tekrarı gibi görünüyor. Değil sekmeli veri - düzenleri için kullanılırsa masalar sadece kötülük vardır. Sekmeli veri DIV bulunuyor kullanarak WC3 bir tarzı ihlalidir.

Bilge, düz SQL (veya AR adlı oluşturulan) çok daha kullanışlı en sitelerinde kullanılacak sorgular,% 80 gibi görünüyor gibi tek bir tekrar bu sayfa yük değil tekrarlanması SELECT (ben script dilleri hakkında konuşuyorum Burada PHP gibi). Neden aşırı vergileri DB sadece kaldırılmadan önce bir kez çalıştırmak için bir açıklama hazırlamak yapmak istiyorsunuz?

MySQL:

A prepared statement is specific to the session in which it was created. If you terminate a session without deallocating a previously prepared statement, the server deallocates it automatically.

Yani senaryonun sonunda PHP bağlantısını otomatik kapanacak ve yalnızca komut sonraki yüküne yeniden oluşturulan sahip hazırlanmış deyimi kaybedersiniz.

Ben bir şey eksik veya bu performansı azaltmak için sadece bir yoludur muyum?

: GÜNCELLEME:

Ben her komut dosyası için yeni bağlantıları varsayarak yaşıyorum kafama dank etti. Ben kalıcı bir bağlantısı kullanıldığında ise daha sonra bu sorunlar yok olacağını varsayıyorum. Bu doğru mudur?

: Update2:

Onlar not a very good option web çoğu içindir - - hareketleri kullanabilirsiniz, özellikle eğer kalıcı bağlantılarının çözüm bile görünüyor. Yani silbaştan gitmek için aşağıdaki kriterler başka bir şey sahip değilim ...

: Update3:

Çoğu kişi sadece ifade tam sorunu açıklamak değil "hazırlanmış deyimleri SQL enjeksiyon karşı korumak" tekrarlayın. Her DB kütüphane için sağlanan "kaçış" yöntemi also protects against SQL injection. Ama bundan daha fazladır:

When sending a query the normal way, the client (script) converts the data into strings that are then passed to the DB server. The DB server then uses CPU power to convert them back into the proper binary datatype. The database engine then parses the statement and looks for syntax errors.

When using prepared statements... the data are sent in a native binary form, which saves the conversion-CPU-usage, and makes the data transfer more efficient. Obviously, this will also reduce bandwidth usage if the client is not co-located with the DB server.

...The variable types are predefined, and hence MySQL take into account these characters, and they do not need to be escaped.

http://www.webdesignforums.net/showthread.php?t=18762

Nihayet bu konuda boğaz beni ayarlanması için OIS sayesinde.

8 Cevap

CSS tablolar tartışmanın aksine, hazırlanan tablolar ile net güvenlik etkileri vardır.

Bir sorguya kullanıcı tarafından sağlanan verileri koymak için tek yol olarak hazırlanmış ifadeler kullanmak eğer SQL enjeksiyon gelince, o zaman kesinlikle kurşun geçirmez.

Eğer veritabanı üzerinde bir sql deyimi çalıştırdığınızda, sql ayrıştırıcı hazırlanması gibi aynı süreç olduğu, önceden bunu analiz etmek gerekir.

Yani, doğrudan hazırlama ve yürütme sql ifadeleri yürütme karşılaştıran hiçbir dezavantajları vardır, ama bazı avantajları:

  • Her şeyden önce, longneck önce de belirtildiği gibi, bir hazır deyimi kullanıcı girişini geçtikten otomatik giriş kaçar. Veritabanı değerleri için filtreleri hazırlanmış ve uygun sadece bu değerlere izin var sanki.

  • Kullanımı iyice tablolarını hazırlamıştır, ve bunu birden çok kez çalıştırmak için gereken duruma geleceğini İkincisi ise, hazırlamak ve yürütmek için kodu yeniden yazmak gerekmez, ama sadece çalıştırmak.

  • Üçüncüsü: eğer uygun yapılırsa kodu daha okunabilir hale gelir:


$sql = 'SELECT u.id, u.user, u.email, sum(r.points)
        FROM users u
        LEFT JOIN reputation r on (u.id=r.user_id)
        LEFT JOIN badge b on (u.id=b.user_id and badge=:badge)
        WHERE group=:group';

$params = array(
    ':group' => $group, 
    ':badge' => $_GET['badge']
);

$stmt = $pdo->prepare($sql);
$result = $stmt->execute($params);


Yerine


$sql = 'SELECT u.id, u.user, u.email, sum(r.points)
        FROM users u
        LEFT JOIN reputation r on (u.id=r.user_id)
        LEFT JOIN badge b on (u.id=b.user_id and badge="'.mysql_real_escape_string($_GET['badge']).'")
        WHERE group="'.mysql_real_escape_string($group).'"';

$result = mysql_query($sql);


Eğer favori olacağını kod sql deyimi, değiştirmek zorunda düşünün? ;-)

Hazırlanan Tablolar çeşitli durumlarda kullanışlı gelebilir:

  • Güvenilmeyen kullanıcı verilerine sorgu veri Büyük ayrılması.
  • Performans artışı, aynı sorgu birden çok kez çalıştırıldığında
  • Geleneksel sorgu kodlama ve böyle yaparak sona erecek ise ikili veriler hazırlanmış ifadesi olarak iletiliyor performans artışı, ikili protokolünü kullanabilirsiniz.

Şimdi geri forths iki yapmak zorunda gibi (ikili hiçbir veri tekrarlanan değil) normal şartlar altında vurmak bir performans var. Sorgu "hazırlamak" için ve ikinci sokulacak veriler ile birlikte belirteci iletmek için ilk. Çoğu kişi, güvenlik yararına bu fedakarlığı yapmaya hazırız.

With regards to persistent connections: MySQL has one of the fastest connection build up times on the market. It's essentially free for most set ups, so you're not going to see too much of a change using persistent connections or not.

Cevap güvenlik ve soyutlama ile ilgisi yoktur. Herkes zaten güvenliği söz vardır, ama gerçek ters, giriş tamamen sorguda kendisini soyutlanmış olmasıdır. Giriş inlining genellikle bir veritabanı bağımlı bir işlem ise bu, bir soyutlama katmanı kullanarak gerçek bir veritabanı bilinemezciliğe sağlar. Eğer taşınabilirlik için bir şey veriyorsan, hazırlanan tablolar gitmek için yoludur.

Gerçek dünyada, ben nadiren hiç dml sorguları yazmak. Benim İNSERTLER / tüm güncelleştirmeleri otomatik olarak soyutlama katmanı tarafından inşa edilmiştir ve sadece bir giriş dizisi geçirerek tarafından yürütülür. Tüm niyet ve amaçlar için, gerçekten sorguları hazırlama ve daha sonra (ilk bağlantı gecikme için tasarruf HAZIRLIYOR) bunları yürütme için "performans isabet" var. Bir UDS (Unix Alanı Soket) bağlantısı kullanırken Ama bir fark (hatta kriter edebilmek) için gitmiyoruz. Bir kaç mikrosaniye sırasına genellikle bulunuyor.

Güvenlik ve soyutlama upsides önüne alındığında, ben pek savurgan derim.

Performans yararı az ayrıştırma gelmez - sadece tekrar tekrar erişim yolları hesaplamak zorunda kez yerine geliyor. Eğer sorgular binlerce veren olduğunuzda bu çok yardımcı olur.

Mysql'in çok basit iyileştirici / planlayıcısı göz önüne alındığında bu çok daha sofistike optimize ile daha olgun bir veritabanı ile daha az sorun olabilir.

Veri çarpıklıklar farkında olan gelişmiş bir iyimserlik var, ancak bu performans yarar aslında bir zararına dönüşebilir. Bu durumda sık sık farklı değişmez değerleri kullanarak yerine önceden bir yolunu yeniden Aynı sorgu için farklı bir erişim yolu ile getting daha iyi olabilir.

When using sql queries like SELECT x,y,z FROM foo WHERE c='mary had a little lamb' the server has to parse the sql statement including the data + you have to sanitize the "mary had..." part (a call to mysql_real_escape() or similar for each parameter). Using prepared statements the server has to parse the statement, too, but without the the data and sends back only an identifier for the statement (a tiny tiny data packet). Then you send the actual data without first sanitizing it. I don't see the overhead here, though I freely admit I've never tested it. Have you? ;-)

edit: Ve hazırlanmış deyimleri kullanarak dizelerine (giriş / çıkış) her parametre dönüştürme ihtiyacını ortadan kaldırabilir. Muhtemelen daha çok eğer mysqlnd (yerine istemci kütüphanesi libmysql "eski") php kullandığı sürümü. Ya bu performans yönünü test değil.

Bu mater veya hazırlanmış deyimleri - Ben kalıcı bağlantıları kullanmak için herhangi bir iyi avantajlar bulma gibi görünmüyor. Bu rakamlara bak - (! Bir sayfa isteği asla olmayacak) 6000 select tablolar için zar zor fark söyleyebilir. Benim sayfaların en az 10 sorguları kullanın.

UPDATED I just revised my test to include 4k SELECT and 4k INSERT statements! Run it yourself and let me know if there are any design errors.

Benim MySQL sunucusu Apache gibi aynı makinede çalışan olmasaydı belki fark daha büyük olurdu.

Persistent: TRUE
Prepare: TRUE
2.3399310112 seconds

Persistent: FALSE
Prepare: TRUE
2.3265211582184 seconds

Persistent: TRUE
Prepare: FALSE
2.3666892051697 seconds

Persistent: FALSE
Prepare: FALSE
2.3496441841125 seconds

İşte benim test kodu:

$hostname = 'localhost';
$username = 'root';
$password = '';
$dbname = 'db_name';

$persistent = FALSE;
$prepare = FALSE;

try 
{

    // Force PDO to use exceptions for all errors
    $attrs = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);

    if($persistent) 
    { 
    	// Make the connection persistent
    	$attrs[PDO::ATTR_PERSISTENT] = TRUE;
    }

    $db = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password, $attrs);

    // What type of connection?
    print 'Persistent: '.($db->getAttribute(PDO::ATTR_PERSISTENT) ? 'TRUE' : 'FALSE').'<br />';
    print 'Prepare: '.($prepare ? 'TRUE' : 'FALSE').'<br />';

    //Clean table from last run
    $db->exec('TRUNCATE TABLE `pdo_insert`');

}
catch(PDOException $e)
{
    echo $e->getMessage();
}

$start = microtime(TRUE);

$name = 'Jack';
$body = 'This is the text "body"';

if( $prepare ) {

    // Select
    $select = $db->prepare('SELECT * FROM pdo_insert WHERE id = :id');
    $select->bindParam(':id', $x);

    // Insert
    $insert = $db->prepare('INSERT INTO pdo_insert (`name`, `body`, `author_id`) 
    VALUES (:name, :body, :author_id)');
    $insert->bindParam(':name', $name);
    $insert->bindParam(':body', $body);
    $insert->bindParam(':author_id', $x);


    $run = 0;
    for($x=0;$x<4000;++$x) 
    {
    	if( $insert->execute() && $select->execute() ) 
    	{
    		$run++;
    	}
    }

}
else
{

    $run = 0;
    for($x=0;$x<4000;++$x) {

    	// Insert
    	if( $db->query('INSERT INTO pdo_insert (`name`, `body`, `author_id`) 
    	VALUES ('.$db->quote($name).', '. $db->quote($body).', '. $db->quote($x).')') 

    	AND

    	// Select
    	$db->query('SELECT * FROM pdo_insert WHERE id = '. $db->quote($x)) )
    	{
    		$run++;
    	}

    }

}





print (microtime(true) - $start).' seconds and '.($run * 2).' queries';

Cassy hakkıdır. Derlemek / hazırlamak yoksa, dbms çalıştırmak mümkün önce herhangi bir durumda olurdu.

Ayrıca, avantajı hazırlamak sonucunu kontrol edebilir ve başarısız hazırlamak eğer algo başarısız sorguyu çalıştırmak için db kaynakları israf etmeden bir istisna tedavisinde kapalı şube olduğunu.