SQL performans vs temiz OO-yapısı

13 Cevap php

PHP programlama yaparken ben her zaman anlamlı 'modelleri' veritabanındaki tablolara karşılık (sınıflar) oluşturmaya çalışın. Sık sık şu sorunla karşılaşırsanız:

authors ve blogs, hem benim uygulamada karşılık gelen bir model var: Ben iki tablo ile bir veritabanı oluşturduk varsayarsak.

Diyelim ki yazar hakkında bilgilerle birlikte tüm bloglar yazdırmak istiyorum diyelim, ben böyle bir şey yapmak zorunda olurdu:

<?php
foreach ($app->getBlogs() as $blog) {
  echo "<h1>" . $blog->title . "</h1>";
  echo "Written by" . $blog->getAuthor()->name . "</p>";
  // ... et cetera
}
?>

Sorun olduğunu uygulama şimdi yangın 1 SQL tüm blog öğeleri almak için sorgu ve [blog öğelerin sayısı] sorguları her yazar için bilgi almak için. Ben basit bir sorgu kullanarak bu bilgileri aldıktan olabilirdi basit SQL kullanılır olması:

SELECT * FROM blogs
JOIN authors ON authors.id = blogs.author

Ne tür sorunları ile ilgili en iyi yolu: çok gereksiz SQL sorguları yürütme olmadan bir nesne tabanlı uygulama geliştirme.

13 Cevap

IMO, ben sadece ne var taşırken, başka bir sınıf yazmak gerektiğini düşünüyorum. Her zaman bir yazar için bir blog için mantıklı mı? Her yazar bir blog var mı? Bir yazar birden bloglar olabilir? Sonra bu encapsulate bir sınıf tasarımı, bu konular hakkında düşünün. Tipik bir veritabanı şemaları OO ... onlar ilişkisel değil, unutmayın. Evet, yakın, ancak ince farklılıklar vardır.

Bir yazar birden çok blog var eğer Yani, (yazar kimliği dayalı tuşu ile) bir çeşit sınıf birden çok değerli bir anahtar olabilir ve tek bir SQL çağrısı ile bu sınıf başlatmak ya da yükleyebilirsiniz. Düşünmek sadece bazı şeyler.

Eğer verimsiz sql işlemleri, gereksiz yineleme ya da etkilenen satır sayısı olarak hiçbir gerçek etkisi olacak bir gerçeği bilmek için sürece her zaman, örneğin bir aile içinde çocuk sayısının üzerinde bir operasyon yineleme (küçük olacak ki, kısa Duggars gibi çok nadir durumlarda, 10'dan az) olması üzerine dayanıyordu olabilir, ben hep OO kod güzelliği üzerinde ilişkisel sorgu verimliliğini tercih var.

Çirkin OO kod bakım bir ağrı yapabilir de, verimsiz veri erişim Eğer tatil veya uyumaya çalışırken konum zaman genellikle, onun dizlerine bir sistem getirebilir. Ve çoğu zaman, size en verimli SQL işlemleri makul "objecty" arayüze sahip kılan iyi bir uzlaşma bulabilirsiniz. Bu üstlenmeden veya nesne modeli güzel değilse özellikler ekleyerek gelince size biraz daha fazla zamana mal olabilir, ama çalıştırmak büyük donanım açısından her tek o düğmeye zaman (veya para müşterilerinizin zaman mal oluyor app - optimizasyon asla iyi bir yöntem) ve uygulamayı kullanarak harcanan adam saat kadar (bir umut ediyorum) gelişmekte koymak adam saat geçmek gerekir.

Bildiğim kadarıyla bir arayüz (tüm olası tüketim alışkanlıklarını anlamaya zorlayarak) gerekli olup olmadığı hakkında kaygıları gibi, ben üzerinden saklanan prosedürleri tüm veri değişikliği yaparak bu ele, ancak veri erişim tabloları ve karşı düz gitmek için izin var ; tüm kullanıcılara seçme ayrıcalığı yalnızca vererek bakıldı. Birçok insan tüm sql çalıştırmak olmak onların standartlarına olmasını sağlamak adına aşağı tüketicilerin tüm veri erişim operasyonlarını kilitlemek istiyorum gibi bu, bir yarı tartışmalı bir pozisyon. Ama verilere bakarak yeni yollar her zaman geliyor ve yeni bir saklı yordam eklemek varsa, çekirdek sınıf kütüphaneleri güncelleştirmek ve istemci kod birisi yeni bir özelliği uygulamak istiyor her zaman güncellemek edilir, dağıtım ve yeterlilik büyüyebilir dini ideali uymayan bir nesne modeli ile uğraşmak zorunda çok daha fazla - gerçek bir yük olacak. Ve bu aşağı tüketiciler tarafından yazılmış yeni select ifadeleri koşer olduğunu doğrular bir kod muayene işlemini uygulamak için çok daha kolay.

Ben büyük bir ORM savunucusu değilim, ve burada benim tartmak bulunuyor:

Bu geliştirici performansı bir ton için uygulama performansı bir inperceptible miktarda işlem tamam. Sunucular bu gün son derece güçlü olduğunu ve ekstra demir bize bazı yeni esneklik verir.

Eğer onun diz sunucuyu getirerek kullanıcı deneyimini ortadan kaldırdığını aptalca bir şey yaparsam söyledi, o tamam artık bulunuyor. Eğer kendi alanlarında bütün ve birlikte hepsini aşağı çekerek, sizin örnekte bir milyon yazarlar olsaydı onlara yineleme akıllıca olacaktır. Eğer sadece 20 yazar olsaydı, o zaman hiç önemli değil.

Büyük veri setlerinin ve pahalı toplu işlemleri durumunda, hatta bir ORM adam olarak, ben sadece bu durum için özel sprocs veya SQL ifadeleri optimize etmek ve yazmak zorunda. Ve bunu ben set büyük bir veri aşağı çekin ve o kapalı çalışacak bir önbelleğe alma desen kullanmak daha iyi olurdu ben veritabanını çekiç böyle bir şekilde benim kod yazmak için dikkatli olmak zorunda.

Bu devam tartışmayı bir büyük, ama bana sadece tek bir aracı ile her sorunu çözemez anlayış meselesi.

Bu gibi şeyler, kendi veri katmanı oluşturmak sizin için çözmek gerektiğini tam olarak nelerdir. Bloglar için modelde, her bir sorguda blog başlıkları ve yazarın adını dönecektir getBlogList gibi bir işlev () olmalıdır.

Kullanmak ne olursa olsun çözelti, bu durumda, tek bir seçim verilmesi durumunda ORM ya da değil, yeteneğine sahip olmalıdır ve aynı zamanda sadece gerekli sütunları seçme yeteneğine sahip olmalıdır. Sonra bu gelen bu yazarın başına bloglar listeleri karşılık gelen yazarlar nesneleri doldurma yeteneğine sahip olmalıdır katılın. Birden fazla SQL verecek olması savurgan olduğunu.

Tahrik bu ile başa çıkabilecek bir PHP ORM bir örnektir. Ben ona hiç bakmadım gerçi, Doktrin bunu gerekir eminim.

Neden tekerleği yeniden icat?

Ben diğer bazı bağlamaları .. Örnek kullandı:

<?php
$blogs = $app->getBlogs();
$blogs->getAuthor();
foreach ($blogs as $blog) {
  echo "<h1>" . $blog->title . "</h1>";
  echo "Written by" . $blog->getAuthor()->name . "</p>";
  // ... et cetera
}
?>

- $ Blogda> getAuthor () çağrısı sadece bir kez DB sorgular ve dizi için özel bir nesne kullanarak, getAuthor () çağrısı üzerine her denir (ama, nedense sadece tek bir sorgu çalıştırmak için optimize edilmiştir).

Zaten soruyu yanıtladı ettik:

Ben basit bir sorgu kullanarak bu bilgileri aldıktan olabilirdi basit SQL kullanılır olması

Sen only blog ve blog yazılarını and yazarlar getirir SQL getirir SQL arasında bir seçim var. Aynı şekilde just blog veya blog mesajları and yazarlar getirir PHP kodu getirir bazı PHP kodu arasında bir seçim var. Eğer SQL konusunda bir seçim yapmak zorunda gibi, PHP kodu ile ilgili bir seçim yapmak zorunda.

Bu pratikte işe nasıl göstermek yukarıda örnekler bol miktarda vardır. Doktrini veya Propel kullanmak için öneri de iyi biridir.

Bu klasik ORM sorundur. Düşünce Pek çok okul. Php özelliklerini emin, ama bu sorunu çözmek için çeşitli stratejiler vardır Değil 'empedans uyumsuzluğu.' Google orm.

Bunu yapmanın tek yolu ona katılmak ve blog ve yazar için veri içeren başka bir sınıf görünümü sonuçlarını eşleştirmek qith bir görünüm yaratmak için olduğunu.

Dürüst olmak gerekirse, sadece getBlogsWithAuthors denilen blog sınıf (bir yöntem oluşturmak) ve daha sonra çalıştırın

SELECT  *
FROM    blogs
JOIN    authors 
        ON authors.id = blogs.author

Ben her model sınıfı için bu gibi şeyler yazmak için bir ağrı gibi görünebilir biliyorum, ama başka bir yol gerçekten yoktur. Ancak, biraz daha dinamik yapabilir:

//this is a method of a model class. 
//Assume $this->table is the table name of the model (ie, Blog)
public function getWith($joinTable, $pivot1, $pivot2)
{
    $sql="SELECT    *
            FROM    {$this->table}
            JOIN    $joinTable 
                    ON $pivot1 = $pivot2";

    return executeQuery($sql);    
}

$blog=new Blog();
$result=$blog->getWith('authors', 'authors.id', 'blogs.author');
[play with results here]

Her zaman bir ara katman olarak memcached kullanabilir. Her sorgu istediğiniz gibi pek çok çalıştırmak anlamına gelir, tamamen RAM tabanlı olacaktır.

Greg Young ve Martin Fowler tarafından açıklandığı gibi Komutanlığı / Sorgu Ayırma düşünün. Sizin sorgu modeli blog ve Yazar sunum katmanı için DTOs almak için optimize edilmiş tek bir tabloya de-normalize olabilir.

Greg Young InfoQ üzerinde CQS üzerinde büyük bir sunum var.