Frage

Im moment ist mein code (PHP) zu viele SQL-Abfragen in es.eg...

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

Ich bin auf der Suche in die Verwendung von gespeicherten Prozeduren zu reduzieren und machen die Dinge ein wenig robuster, aber ich habe einige Bedenken..

Ich habe Hunderte von verschiedenen Fragen rund um die Website, und viele von Ihnen sind sehr ähnlich.Wie sollte ich verwalten alle diese Fragen, wenn Sie entfernt werden, aus Ihrem Kontext (den code, mithilfe der Ergebnisse) und platziert in eine gespeicherte Prozedur in der Datenbank?

War es hilfreich?

Lösung

Die beste Vorgehensweise für Sie hängt davon ab, wie Sie nähern sich Ihre Daten zugreifen.Es gibt drei Ansätze, die Sie ergreifen können:

  • Die Verwendung von gespeicherten Prozeduren
  • Halten Sie die Abfragen in den code (aber legen Sie alle Ihre Abfragen in Funktionen und reparieren alles, was zu verwenden PDO Parameter, wie bereits erwähnt)
  • Verwenden Sie ein ORM-tool

Wenn Sie möchten, übergeben Sie Ihre eigenen raw-SQL, um die Datenbank-engine dann die gespeicherten Prozeduren wäre der Weg zu gehen, wenn alles, was Sie tun möchten ist, bekommen die raw-SQL aus Ihrem PHP-code, aber halten Sie es relativ unverändert.Die gespeicherten Prozeduren vs raw-SQL-Debatte ist ein bisschen von einem Heiligen Krieg, aber K.Scott Allen macht einen ausgezeichneten Punkt, wenn auch ein Wegwerf-eines - in einem Artikel über Versionierung Datenbanken:

Zweitens, gespeicherte Prozeduren haben gefallenen aus der Gunst in meinen Augen.Ich kam von der WinDNA Schule der Indoktrination, der sagte, gespeicherten Prozeduren sollten benutzt werden, die ganze Zeit.Heute sehe ich gespeicherte Prozeduren als ein API-layer für die Datenbank.Dies ist nützlich, wenn Sie benötigen eine API-Schicht auf der Datenbank-Ebene, aber ich sehe viele Anwendungen den Verarbeitungsaufwand, der Erstellung und Pflege einer extra-API-Schicht, die Sie nicht brauchen.In diesen Anwendungen gespeicherte Prozeduren sind eher eine Belastung als ein Vorteil.

Ich Neige dazu zu neigen, die nicht mithilfe von gespeicherten Prozeduren.Ich habe gearbeitet, in Projekten, wo die DB hat eine API ausgesetzt durch gespeicherte Prozeduren, aber gespeicherte Prozeduren kann verhängen einige Einschränkungen von Ihrem eigenen, und diese Projekte haben alle, in unterschiedlichem Maße verwendet dynamisch generiert, raw SQL in den code zum Zugriff auf die DB.

Mit einer API-Schicht auf der DB gibt bessere Abgrenzung der Zuständigkeiten zwischen der DB-team, und das Dev-team auf Kosten von einigen der Flexibilität, die Sie haben würden, wenn die Abfrage, die in gehalten wurde, der code, jedoch in PHP-Projekten sind weniger wahrscheinlich, um die beträchtlichen genug teams profitieren von dieser Abgrenzung.

Begrifflich, sollten Sie wahrscheinlich Ihre Datenbank unter Versionskontrolle.Praktisch gesprochen, allerdings, Sie sind viel eher habe gerade Ihren code versioniert, wie Sie Ihre Datenbank unter Versionskontrolle.Sie werden wahrscheinlich ändern Sie Ihre Abfragen, wenn Sie änderungen an Ihrem code, aber wenn Sie ändern Sie die Abfragen in gespeicherten Prozeduren gespeichert, die für die Datenbank, dann werden Sie wahrscheinlich nicht Prüfung diejenigen, die in, wenn Sie überprüfen Sie den code und verlieren Sie viele der Vorteile der Versionierung, die für einen erheblichen Bereich Ihrer Anwendung.

Unabhängig davon, ob oder nicht Sie wählen Sie nicht gespeicherte Prozeduren verwenden, obwohl, Sie sollten zumindest sicherstellen, dass jede Datenbank, der Betrieb ist gespeichert in eine unabhängige Funktion, sondern als eingebettet in jedes Ihrer Seite die Skripte - im wesentlichen eine API-Schicht für die DB, die ist gepflegt und versioniert mit Ihrem code.Wenn Sie gespeicherte Prozeduren, wird dies effektiv bedeuten, dass Sie zwei API-Ebenen für die DB, eine mit dem code und eine mit der DB, die Sie fühlen sich vielleicht unnötig kompliziert Dinge, wenn Ihr Projekt keine eigenen teams.Ich sicherlich tun.

Wenn das Problem einen code Ordnung ist, gibt es Möglichkeiten, um code mit SQL-eingeklemmt in der es mehr vorzeigbar, und die UserManager-Klasse unten gezeigt wird, ist ein guter Weg, um zu beginnen - die-Klasse enthält nur Abfragen die sich auf die 'user' - Tabelle, jede Abfrage hat seine eigene Methode in der Klasse und die Abfragen sind eingerückt in die prepare-Anweisungen formatiert und, wie würden Sie, formatieren Sie Sie in einer gespeicherten Prozedur.

// 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'];

Jedoch, wenn Ihre Abfragen sind ziemlich ähnlich, aber Sie haben eine riesige Anzahl von Permutationen in Ihre Abfrage-Bedingungen wie kompliziert paging, Sortierung, Filterung, etc., ein Object/Relational mapper tool ist wahrscheinlich der Weg zu gehen, obwohl der Prozess der überholung Ihrer bestehenden code zu nutzen, das tool kann ganz schön kompliziert sein.

Wenn Sie entscheiden, zu untersuchen, ORM-tools, sollte man sich ansehen, Treiben, die ActiveRecord-Komponente Yii, oder der König-daddy PHP ORM, Lehre.Jede von diesen bietet Ihnen die Möglichkeit, programmgesteuert erstellen von Abfragen für Ihre Datenbank mit allen Arten von komplizierten Logik.Lehre ist die voll ausgestattete, so dass Sie zur Vorlage Ihrer Datenbank mit Dinge wie die Geschachtelte Satz Baum-Muster out of the box.

In Bezug auf Leistung, gespeicherte Prozeduren sind die schnellsten, aber in der Regel nicht viel über raw-sql.ORM-Werkzeuge kann erhebliche Auswirkungen auf die Leistung in einer Reihe von Möglichkeiten, ineffizient oder redundante Abfragen, riesige file-IO beim laden der ORM-Bibliotheken für jede Anfrage, die dynamische SQL-Generierung auf jede Abfrage...alle diese Dinge einen Einfluss haben kann, aber die Verwendung eines ORM-tool kann drastisch erhöhen die Leistung zur Verfügung, um Sie mit einer viel kleineren Menge an code, die als die Erstellung Ihrer eigenen DB-Schicht mit manuellen Abfragen.

Gary Richardson ist absolut richtig, obwohl, wenn Sie gehen, um weiterhin die Verwendung von SQL in Ihrem code sollten Sie immer mit PDO, vorbereiteten Anweisungen, um Griff die Parameter unabhängig davon, ob Sie eine Abfrage oder eine gespeicherte Prozedur.Die Entkeimung der Eingabe durchgeführt wird, wird Sie von PDO.

// 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);

VORBEHALT:unter der Annahme, dass die ID 1 ist, wird das obige Skript ausgegeben wird string(1) "1". PDO->lastInsertId() gibt die ID als string, unabhängig davon, ob die Spalte eine Ganzzahl ist oder nicht.Dies wird wahrscheinlich nie ein problem sein für dich als PHP-führt casting von Zeichenfolgen in Ganzzahlen automatisch.

Die folgende Ausgabe bool(true):

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

aber wenn Sie code haben, der erwartet, dass die Wert auf eine ganze Zahl sein, wie is_int oder PHP "wirklich 100% gleich" Betreiber:

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

Sie könnten in einige Probleme.

Edit: Einige gute Diskussionen, die auf gespeicherten Prozeduren hier

Andere Tipps

Als erstes sollten Sie verwenden Platzhalter in der Abfrage stattdessen der Interpolation der Variablen direkt.PDO/MySQLi erlauben, Sie zu schreiben Sie Ihre Abfragen wie:

SELECT * FROM sometable WHERE iUser = ?

Die API wird sicher ersetzen Sie die Werte in die Abfrage.

Ich habe auch lieber meine Abfragen in den code anstelle der Datenbank.Es ist viel einfacher zu arbeiten mit RCS bei der die Abfragen werden mit Ihrem code.

Ich habe eine Faustregel, die bei der Arbeit mit ORM ist:wenn ich arbeite mit einer Entität zu einer Zeit, ich werden verwenden Sie die Schnittstelle.Wenn ich Berichte/arbeiten mit Datensätzen in der Gesamtheit, den ich in der Regel schreiben von SQL-Abfragen, es zu tun.Dies bedeutet, dass es sehr wenige Anfragen in meinem code.

Ich musste Aufräumen ein Projekt, welches viele (identische/ähnliche) Abfragen, gespickt mit injection.Die ersten Schritte, die ich nahm, wurden mit Hilfe von Platzhaltern und dem label an jeder Abfrage mit dem Objekt/Methode und Quellen-Zeile der Abfrage erstellt wurde.(Legen Sie die PHP-Konstanten METHODE und LINE in einen SQL-Kommentar-line)

Es sah so etwas wie dieses:

-- @Line:151 "userclass" gezeigt::getuser():

SELECT * FROM USERS;

Protokolliert alle Abfragen für eine kurze Zeit lieferte mir einige Ansatzpunkte auf, welche Abfragen Zusammenführen.(Und wo!)

Ich würde verschieben Sie alle SQL auf einem separaten Perl-Modul (.pm) Vielen Anfragen konnte die Wiederverwendung der gleichen Funktionen, mit leicht unterschiedlichen Parametern.

Ein häufiger Fehler für die Entwickler ist, Tauchen Sie ein in ORM-Bibliotheken, parametrisierten Abfragen und gespeicherte Prozeduren.Wir arbeiten dann für Monate in einer Reihe um den code "besser", aber es ist nur "besser" in einer Entwicklung Art und Weise.Sie machen nicht alle neuen Funktionen!

Verwenden Sie Komplexität in Ihrem code nur zu Adresse die Bedürfnisse der Kunden.

Verwenden Sie ein ORM-Paket, jeden halbwegs anständigen Paket ermöglicht es Ihnen,

  1. Holen Sie sich einfache Ergebnis-sets
  2. Halten Sie Ihre komplexe SQL-nahe Datenmodell

Wenn Sie haben eine sehr komplexe SQL, dann ist auch die Sicht schön zu machen es mehr vorzeigbar zu den verschiedenen Schichten der Anwendung.

Wir waren in einer ähnlichen Notlage zu einer Zeit.Wir abgefragt haben eine bestimmte Tabelle in einer Vielzahl von Möglichkeiten, über 50+.

Was wir am Ende getan haben, war die Schaffung eines einzigen Fetch-gespeicherte Prozedur, die einen parameter enthält den Wert für die WhereClause.Die WhereClause wurde gebaut in Anbieter-Objekt, Beschäftigten wir-die-Fassade-design-Muster, wo wir konnten Peeling für jede SQL-injection-Angriffe.

So weit wie die Wartung geht, ist es leicht zu ändern.SQL Server ist auch ganz chum und speichert die Ausführung der Pläne von dynamischen Abfragen, so das die Gesamtleistung ist ziemlich gut.

Sie ' ll haben zu bestimmen, die Leistung Nachteile, basierend auf Ihrem eigenen system und muss, aber alles und alle, das funktioniert sehr gut für uns.

Es gibt einige Bibliotheken, wie MDB2 in der BIRNE, stellen Sie die Abfrage ein wenig einfacher und sicherer zu machen.

Leider, Sie können ein bisschen wortreich zu set up, und Sie haben manchmal passieren Sie die gleichen Informationen zweimal.Ich habe MDB2 in ein paar Projekte, und ich neigte dazu, schreiben Sie eine dünne Schicht um ihn herum, besonders für die Angabe der Typen der Felder.Ich in der Regel, dass ein Objekt, das weiß, dass zu einer bestimmten Tabelle und Ihre Spalten, und dann eine Hilfsfunktion, die in dieser füllt Feldtypen für mich, wenn ich Sie nennen MDB2-Abfrage-Funktion.

Zum Beispiel:

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

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

    return $Types;
}

Natürlich ist das Objekt hat eine Landkarte der Tabelle Namen -> schemas, die es kennt, und nur extrahiert die Typen der Felder, die Sie angeben, und gibt einen passenden Typ array, geeignet für die Verwendung mit einem MDB2-Abfrage.

MDB2 (und ähnliche Bibliotheken), dann behandeln Sie die parameter-substitution für Sie, so für update/insert-Abfragen, die Sie gerade bauen Sie eine hash-map/aus Spalte name auf den Wert, und verwenden Sie die "autoExecute' - Funktionen zum erstellen und ausführen der entsprechenden Abfrage.

Zum Beispiel:

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);
}

und MDB2 wird die Abfrage erstellen, auf der Flucht alles ordentlich, etc.

Ich würde empfehlen, die Messung der Leistung mit MDB2-obwohl, wie er zieht in ein gutes Stück von code, die möglicherweise Probleme verursachen, wenn Sie nicht mit einer PHP accelerator.

Wie gesagt-das setup-overhead scheint entmutigend auf den ersten, aber sobald es fertig ist, können Sie die Abfragen einfacher/mehr symbolisch zu schreiben und (vor allem) ändern.Ich denke, MDB2 sollten wissen ein bisschen mehr über Ihr schema, das würde simpify einige der Häufig verwendeten API-Aufrufe, aber Sie können reduzieren die ärgernis, das durch die Kapselung des Schemas selbst, wie ich oben erwähnte, und bietet einfach-accessor-Funktionen generieren, dass die arrays MDB2-Anforderungen zum ausführen dieser Abfragen.

Natürlich können Sie nur flache SQL-Abfragen als string mit der query () - Funktion, wenn Sie wollen, Sie sind also nicht gezwungen Schalter auf die volle 'MDB2 Weg - Sie können es ausprobieren, teilen, und sehen, ob Sie es hassen oder nicht.

Diese andere Frage hat auch einige nützliche links, die in ihm...

Verwenden Sie ein ORM-framework wie QCodo - Sie können ganz einfach anzeigen Ihre vorhandene Datenbank

Ich versuche, ziemlich generischen Funktionen und übergeben Sie einfach die Unterschiede in Ihnen.Auf diese Weise haben Sie nur eine Funktion, um Griff die meisten Ihrer Datenbank, WÄHLEN Sie die.Natürlich können Sie erstellen Sie eine weitere Funktion, um Griff alle Ihre EINSÄTZE.

zB.

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;
}

Dies ist nur aus der Spitze von meinem Kopf, aber Sie bekommen die Idee.Es nur verwenden, übergeben Sie der Funktion die erforderlichen Parameter ein:

zB.

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

In diesem Fall $Beiträge ein array von arrays, die für jede Zeile der Tabelle.Dann können Sie einfach mit einer foreach-oder beziehen Sie sich auf das array direkt:

echo $blogposts[0]['title'];
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top