Nasıl SQL sorguları yönetirim

10 Cevap php

Şu anda benim kod (PHP) içinde çok fazla SQL sorguları vardır. örneğin ...

// not a real example, but you get the idea...
$results = $db->GetResults("SELECT * FROM sometable WHERE iUser=$userid");
if ($results) {
    // Do something
}

Ben bu azaltmak ve biraz daha sağlam şeyler yapmak için saklanan prosedürleri kullanarak içine arıyorum, ama bazı endişeleri var ..

Ben web sitesinde kullanmak çevresinde farklı sorgular yüzlerce var ve bunların çoğu oldukça benzer. Onlar kendi bağlamında (sonuçları kullanır kodu) alınır ve veritabanı üzerinde bir saklı yordam yerleştirilir zaman nasıl bütün bu sorguları yönetmek gerekir?

10 Cevap

Sizin için eylem iyi ders size veri erişimi nasıl yaklaştığını bağlıdır. Atabileceğiniz üç yaklaşım vardır:

  • Saklı prosedürleri kullanın
  • Kodunda sorguları tutun (ama fonksiyonları içine tüm sorguları koymak ve parametreler için PDO kullanmak için her şeyi düzeltmek, daha önce belirtildiği gibi)
  • ORM aracını kullanın

Eğer veritabanı altyapısı için kendi ham SQL geçmek istiyorsanız yapmanız gereken istediğiniz tüm PHP kodu dışında ham SQL olsun ama nispeten değişmeden tutmak ise o saklanan prosedürleri gitmek için yol olacaktır. Ham SQL tartışma vs prosedürler saklı kutsal savaşın bir parçasıdır, ama K. Scott Allen mükemmel bir nokta yapar - bir ıskarta bir de olsa - bir makale versioning databases:

İkincisi, saklanan prosedürler gözlerimde lehine dışına düşmüş. Ben saklanan prosedürleri her zaman kullanılması gerektiğini söyledi telkinin WinDNA okuldan geldi. Bugün, ben veritabanı için bir API katmanı olarak saklanan prosedürleri bakın. Eğer veritabanı düzeyinde bir API katmanı gerekiyorsa, bu iyidir, ama onlar gerek yok ekstra bir API katmanı oluşturma ve sürdürmenin yük üstlenmeden uygulamaların çok görüyoruz. Bu uygulamalarda saklanan prosedürleri bir yararı daha yükünün daha vardır.

Ben saklı yordamları kullanarak değil doğru yalın eğilimindedir. Ben DB aracılığıyla saklanan prosedürleri maruz kalan bir API olan projeler üzerinde çalıştık, ama saklanan prosedürler kendi bazı sınırlamalar getirebilir ve bu projeler all var, değişen derecelerde, ham SQL oluşturulan dinamik olarak kullanılabilir DB erişmek için kod.

DB üzerinde bir API tabakası olan DB ekibi ve sorgu kodu tutuldu eğer olurdu esneklik bazı pahasına Dev takım arasında sorumlulukların daha iyi sınırlandırılmasını verir, ancak PHP projeler oldukça büyük olması daha az olasıdır Bu eğrilmelerini yararlanabilecek kadar takım.

Kavramsal olarak, muhtemelen veritabanı sürüm olmalıdır. Pratik konuşma, ancak, çok daha büyük olasılıkla sadece kod veritabanı sürüm için vardır daha sürüm var demektir. Eğer kodu değişiklikleri yapıyoruz sorguları değişen olması muhtemeldir, ama veritabanına karşı saklı saklı yordamlar sorguları değişiyor eğer o zaman muhtemelen kodunu kontrol ederken bu kontrol olmayacak ve siz kaybedersiniz Başvurunuzun önemli bir alan için sürüm yararları çok.

Ne olursa olsun yine de saklı prosedürleri kullanmak için değil tercih olsun veya olmasın, sen en azından her veritabanı işlemi yerine sayfanızın komut her birinin içine gömülü olan daha bağımsız bir işlevi saklanan emin olmalıdır - DB için aslında bir API katmanı olan korunur ve kod ile versiyonlu edilir. Saklı yordamlar kullanıyorsanız, bu etkili size proje ayrı ekipler yoksa gereksiz şeyleri zorlaştırıyor hissedebilirsiniz DB için iki API katmanları, kod ile bir ve DB ile biri var anlamına gelecektir. Kesinlikle yok.

Sorun kod zariflik biri ise, orada daha prezentabl sıkıştı SQL ile kod yapmak için yolu vardır, ve aşağıda gösterilen UserManager sınıf başlamak için iyi bir yoldur - sınıfı yalnızca 'kullanıcı' tablosuna ilgili sorguları içeren, Her sorgu sınıfta kendi yöntemi vardır ve sorgular hazırlamak tablolara girintili ve bir saklı prosedür bunları biçimlendirmek gibi biçimlendirilir.

// UserManager.php:

class UserManager
{
    function getUsers()
    {
        $pdo = new PDO(...);
        $stmt = $pdo->prepare('
            SELECT       u.userId as id,
                         u.userName,
                         g.groupId,
                         g.groupName
            FROM         user u
            INNER JOIN   group g
            ON           u.groupId = g.groupId
            ORDER BY     u.userName, g.groupName
        ');
        // iterate over result and prepare return value
    }

    function getUser($id) {
        // db code here
    }
}

// index.php:
require_once("UserManager.php");
$um = new UserManager;
$users = $um->getUsers();
foreach ($users as $user) echo $user['name'];

Lütfen sorguları oldukça benzer ama vb filtreleme, sıralama, karmaşık çağrı gibi sorgu koşullarda permütasyon büyük sayıda varsa Ancak, bir nesne / ilişkisel mapper aracı, muhtemelen gitmek için yoludur rağmen varolan kodunuzu elden süreci Aletin kullanımı için oldukça karmaşık olabilir.

ORM araçları araştırmak için karar verirseniz, Propel, Yii ActiveRecord bileşeni, ya da kral-baba PHP ORM, Doctrine bakmak gerekir. Bunların her biri, size programlı karmaşık mantığı her türlü ile veritabanı sorguları oluşturmak için yeteneği verir. Doktrin Eğer Nested Set tree pattern kutudan gibi şeyler ile veritabanını şablon sağlayan, en tam özellikli.

Performans açısından, saklanan prosedürler hızlı vardır, ama genellikle çok tarafından değil ham sql üzerinde. Her istek üzerine ORM kütüphaneleri yüklenirken, dinamik SQL üretimi her sorgusuna ... tüm bu şeyler bir etkisi olabilir verimsiz ya da gereksiz sorgulama, büyük dosya IO, ama - ORM araçları şekillerde bir sayısında önemli bir performans etkisi olabilir ORM aracı kullanımı büyük ölçüde elle sorgu ile kendi DB katman oluşturarak daha kod çok daha küçük bir miktarı ile size sunulan gücünü artırabilir.

Ne olursa olsun bir sorgu veya saklı yordam kullanarak konum olsun, her zaman parametreleri işlemek için PDO'su hazırlanmış deyimleri kullanarak olmalıdır kodunuzda SQL kullanmaya devam etmek gidiyoruz Gary Richardson, ama kesinlikle doğru . Giriş sanitisation PDO tarafından sizin için yapılır.

// optional
$attrs = array(PDO::ATTR_PERSISTENT => true);

// create the PDO object
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", $attrs);

// also optional, but it makes PDO raise exceptions instead of 
// PHP errors which are far more useful for debugging
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare('INSERT INTO venue(venueName, regionId) VALUES(:venueName, :regionId)');
$stmt->bindValue(":venueName", "test");
$stmt->bindValue(":regionId", 1);

$stmt->execute();

$lastInsertId = $pdo->lastInsertId();
var_dump($lastInsertId);

İhtar: ID 1 olduğunu varsayarak, yukarıdaki komut çıktısı 'string (1) "1"'. PDO-> lastInsertId () ne olursa olsun gerçek sütun bir tamsayı olup olmadığını bir dizge olarak kimliği döndürür. PHP otomatik olarak tamsayılar dizeleri döküm yapar gibi bu muhtemelen sizin için bir sorun olmayacak.

Aşağıdaki irade çıktı 'bool (true)':

// regular equality test
var_dump($lastInsertId == 1); 

ancak is_int ya da PHP'nin "is really, truly, 100% equal to" operatörü gibi, değeri bir tamsayı olmasını bekliyor kod varsa:

var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);

bazı konularda çalıştırmak olabilir.

Saklı prosedürleri Edit: Bazı iyi bir tartışma here

Önce yukarı, yerine doğrudan değişkenleri interpolasyon sizin sorguda yer tutucuları kullanmalısınız. PDO / MySQLi Eğer gibi sorguları yazmak için izin:

SELECT * FROM sometable WHERE iUser = ?

API güvenle sorgusuna değerlerini değiştirecektir.

Ben de yerine veritabanı kodu benim sorguları olmasını tercih. Sorguları kodu ile zaman bir RCS ile çalışmak çok daha kolay.

ORM en çalışırken ben başparmak bir kural var: Ben bir seferinde bir varlık ile çalışıyorum, ben arayüzünü kullanacağız. Ben agrega kayıtları ile çalışma / rapor veriyorum, ben genellikle bunu yapmak için SQL sorguları yazmak. Bu benim kodunda çok az sorgular var demektir.

Ben birçok sorguları biraz farklı parametrelerle, aynı işlevleri yeniden verebilecek ayrı bir Perl modülü (. Pm) tüm SQL hareket ediyorum.

Geliştiriciler için ortak bir hata ORM kütüphaneleri, parametrized sorguları ve saklanan prosedürleri dalmak için. Daha sonra kod "daha iyi" hale getirmek için bir satırda ay boyunca çalışmak, ancak bu şekilde bir gelişme tür sadece "iyi" bulunuyor. Herhangi bir yeni özellik yapmıyor!

Tek adresi müşteri ihtiyaçlarına kodunuzu karmaşıklığı kullanın.

Bir ORM paketi kullanın, herhangi bir yarım terbiyeli paketi sağlayacak

  1. Basit sonuç kümelerini almak
  2. Veri modeli için karmaşık SQL yakın tutun

Eğer çok karmaşık SQL varsa, görüşlerini de uygulamanın farklı katmanları için daha prezentabl hale getirmek için güzel.

Biz bir seferde benzer bir çıkmaz vardı. Biz, 50 + üzerinde, çeşitli şekillerde de belirli bir tablo sorgulanır.

Ne yapıyor sona whereClause için bir parametre değeri içeren tek bir saklı yordam oluşturmak getir oldu. WhereClause Sağlayıcı nesne inşa edilmiştir, biz Cephe tasarım deseni, istihdam nerede olabilir scrub herhangi bir SQL enjeksiyon saldırıları için.

Yani kadarıyla bakım gider gibi, değiştirmek kolaydır. SQL Server da oldukça chum ve genel performansı oldukça iyi bu kadar dinamik sorgu yürütme planları önbelleğe alır.

Kendi sistemi ve ihtiyaçlarına göre performance sakıncaları belirlemek gerekir, ve tüm ama, bu very well bizim için çalışır.

I had to clean up a project wich many (duplicate/similar) queries riddled with injection vulnerabilities. The first steps I took were using placeholders and label every query with the object/method and source-line the query was created. (Insert the PHP-constants METHOD and LINE into a SQL comment-line)

Bu şey gibi görünüyordu:

- @ Hattı: 151 KullanıcıSınıfı :: GetUser ():

SELECT * FROM USERS;

Kısa bir süre için tüm sorguları günlük birleştirmek için hangi sorguların bazı başlangıç ​​noktaları bana verilen. (Ve burada!)

Biraz daha kolay ve daha güvenli sorgulama yapmak ARMUT böyle mdb2 gibi bazı kütüphaneler vardır.

Ne yazık ki, onlar kurmak için biraz söz olabilir, ve bazen onlara iki kez aynı bilgi geçmek zorunda. Ben projelerin bir çift mdb2 kullandım, ve özellikle alanların türlerini belirtmek için, etrafında ince bir kaplama yazmak eğiliminde. Ben genellikle belirli bir tablo ve sütunlar hakkında bildiği bir nesne, ve sonra ben bir MDB2 sorgu işlevini çağırdığınızda benim için alan türleri doldurur bir yardımcı işlev yapmak.

Örneğin:

function MakeTableTypes($TableName, $FieldNames)
{
    $Types = array();

    foreach ($FieldNames as $FieldName => $FieldValue)
    {
        $Types[] = $this->Tables[$TableName]['schema'][$FieldName]['type'];
    }

    return $Types;
}

Bu konuda bilir, ve sadece belirttiğiniz alan türlerini ayıklar ve bir MDB2 sorgusu ile kullanım için uygun bir eşleştirme tipi dizi döndürür> şemalar - Açıkçası bu nesne tablo adlarının bir haritası vardır.

Güncelleme / insert sorguları için, sadece değer sütun adından bir karma / haritası oluşturmak ve ilgili sorgu oluşturmak ve yürütmek için 'AutoExecute işlevlerini kullanın, böylece MDB2 (ve benzeri kütüphaneler) sonra, sizin için parametre değiştirme kolu.

Örneğin:

function UpdateArticle($Article)
{
    $Types = $this->MakeTableTypes($table_name, $Article);

    $res = $this->MDB2->extended->autoExecute($table_name,
        $Article,
        MDB2_AUTOQUERY_UPDATE,
        'id = '.$this->MDB2->quote($Article['id'], 'integer'),
        $Types);
}

ve MDB2 vb, her şey düzgün kaçan, sorgu inşa edecek

Ben size bir PHP hızlandırıcı çalıştırıyorsanız değilseniz size sorunlara neden olabilecek bir kod adil biraz çeker gibi olsa mdb2 ile performans ölçme tavsiye ederim.

Dediğim gibi, kurulum havai ilk başta zor gibi görünüyor, ama bir kez bitti sorguları yazmak için basit / daha sembolik olması ve (özellikle) değiştirebilirsiniz. Ben MDB2 yaygın olarak kullanılan API çağrıları bazı simpify edeceğini şema, hakkında biraz daha fazla bilgi gerektiğini düşünüyorum, ama ben yukarıda da belirtildiği gibi, şema kendini sarması, ve üretmek basit erişimci işlevleri sağlayarak bu sıkıntı azaltabilir diziler MDB2 bu sorguları gerçekleştirmek gerekiyor.

Eğer parça parça bunu deneyebilirsiniz, ve eğer görmek - Tabii ki sadece isterseniz tam 'MDB2 yolu' üzerinden geçmek zorunda değil yani, sorgu () işlevini kullanarak bir dize gibi düz SQL sorguları yapabilirsiniz nefret ya da değil.

This other question aynı zamanda bazı yararlı bağlantıları vardır ...

Ben oldukça genel işlevlerini kullanmaya çalışın ve sadece onlara farklılıkları geçmek. Bu şekilde sadece SELECT sizin veritabanı çoğu işlemek için bir işlevi var. Açıkçası tüm UçLaRı işlemek için başka bir işlevi oluşturabilirsiniz.

örn.

function getFromDB($table, $wherefield=null, $whereval=null, $orderby=null){
    if($wherefield != null){ $q = "SELECT * FROM $table WHERE $wherefield = '$whereval'"; }
    else { $q = "SELECT * FROM $table"; }
    if($orderby != null){ $q .= " ORDER BY ".$orderby; }

    $result = mysql_query($q)) or die("ERROR: ".mysql_error());
    while($row = mysql_fetch_assoc($result)){
        $records[] = $row;
    }
    return $records;
}

Bu sadece benim başın üst kapalı, ama fikir olsun. Bunu kullanmak için sadece işlevini gerekli parametreleri geçirmek:

örn.

$blogposts = getFromDB('myblog', 'author', 'Lewis', 'date DESC');

Bu durumda $blogposts tablonun her satırı temsil eden bir dizi bir dizi olacak. O zaman sadece bir foreach kullanın veya doğrudan dizi başvurabilirsiniz:

echo $blogposts[0]['title'];

QCodo gibi bir ORM çerçeve kullanmak - kolayca mevcut veritabanı eşleyebilirler