Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como você gerencia consultas SQL


O melhor curso de ação para você dependerá de como você está abordando seu acesso aos dados. Existem três abordagens que você pode adotar:
  • Usar procedimentos armazenados
  • Mantenha as consultas no código (mas coloque todas as suas consultas em funções e corrija tudo para usar PDO para parâmetros, como mencionado anteriormente)
  • Use uma ferramenta ORM

Se você deseja passar seu próprio SQL bruto para o mecanismo de banco de dados, os procedimentos armazenados seriam o caminho a seguir se tudo o que você deseja fazer é obter o SQL bruto do seu código PHP, mas mantê-lo relativamente inalterado. O debate sobre procedimentos armazenados versus SQL bruto é uma guerra santa, mas K. Scott Allen faz um excelente argumento - embora descartável - em um artigo sobre bancos de dados de versão :

Eu tendo a inclinar-me para não usar procedimentos armazenados. Trabalhei em projetos em que o banco de dados tem uma API exposta por meio de procedimentos armazenados, mas os procedimentos armazenados podem impor algumas limitações próprias, e esses projetos têm todos , em vários graus, usava SQL bruto gerado dinamicamente no código para acessar o banco de dados.

Ter uma camada de API no banco de dados oferece melhor delineamento de responsabilidades entre a equipe de banco de dados e a equipe de desenvolvimento às custas de alguma flexibilidade que você teria se a consulta fosse mantida no código, no entanto, projetos PHP são menos propensos a ter tamanho equipes suficientes para se beneficiar desse delineamento.

Conceitualmente, você provavelmente deveria ter seu banco de dados versionado. Na prática, no entanto, é muito mais provável que você tenha apenas seu código versionado do que seu banco de dados. É provável que você esteja alterando suas consultas ao fazer alterações em seu código, mas se estiver alterando as consultas em procedimentos armazenados armazenados no banco de dados, provavelmente não fará check-in quando fizer check-in do código e perderá muitos dos benefícios do controle de versão para uma área significativa de seu aplicativo.

Independentemente de você optar ou não por não usar procedimentos armazenados, você deve pelo menos garantir que cada operação de banco de dados seja armazenada em uma função independente em vez de ser incorporada em cada um dos scripts de sua página - essencialmente uma camada de API para seu banco de dados que é mantido e versionado com seu código. Se você estiver usando procedimentos armazenados, isso significará efetivamente que você tem duas camadas de API para seu banco de dados, uma com o código e outra com o banco de dados, o que pode complicar desnecessariamente as coisas se seu projeto não tiver equipes separadas. Eu certamente faço.

Se o problema for de limpeza de código, existem maneiras de tornar o código com SQL preso nele mais apresentável, e a classe UserManager mostrada abaixo é uma boa maneira de começar - a classe contém apenas consultas relacionadas à tabela 'usuário', cada consulta tem seu próprio método na classe e as consultas são recuadas nas instruções de preparação e formatadas como você as formataria em um procedimento armazenado.
// 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'];

No entanto, se suas consultas são bastante semelhantes, mas você tem um grande número de permutações em suas condições de consulta, como paginação complicada, classificação, filtragem etc., uma ferramenta de mapeador de objeto/relacional é provavelmente o caminho a seguir, embora o processo de revisão do código existente fazer uso da ferramenta pode ser bastante complicado.

Se você decidir investigar as ferramentas ORM, deve consultar Propel , o componente ActiveRecord de Yii , ou o PHP ORM rei-pai, Doutrina . Cada um deles oferece a capacidade de criar consultas programaticamente em seu banco de dados com todos os tipos de lógica complicada. O Doctrine é o mais completo, permitindo que você molde seu banco de dados com coisas como o Conjunto Aninhado padrão de árvore sai da caixa.

Em termos de desempenho, os procedimentos armazenados são os mais rápidos, mas geralmente não muito em relação ao sql bruto. As ferramentas ORM podem ter um impacto significativo no desempenho de várias maneiras - consultas ineficientes ou redundantes, E/S de arquivos enormes ao carregar as bibliotecas ORM em cada solicitação, geração dinâmica de SQL em cada consulta... o uso de uma ferramenta ORM pode aumentar drasticamente o poder disponível para você com uma quantidade muito menor de código do que criar sua própria camada de banco de dados com consultas manuais.

Gary Richardson está absolutamente certo, porém, se você vai continuar a usar SQL em seu código, você deve sempre usar as instruções preparadas do PDO para manipular os parâmetros, independentemente de estar usando uma consulta ou um procedimento armazenado. A higienização dos insumos é realizada para você pelo DOP.
// 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);

Advertência:supondo que o ID seja 1, o script acima produzirá string(1) "1" . PDO->lastInsertId() retorna o ID como uma string, independentemente de a coluna real ser um número inteiro ou não. Isso provavelmente nunca será um problema para você, pois o PHP executa a conversão de strings para inteiros automaticamente.

O seguinte produzirá bool(true) :
// regular equality test
var_dump($lastInsertId == 1); 

mas se você tiver um código que espera que o valor seja um número inteiro, como is_int ou PHP "é realmente, verdadeiramente, 100% igual a" operador:
var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);

você pode ter alguns problemas.

Editar: Algumas boas discussões sobre procedimentos armazenados aqui