Ir para conteúdo

POWERED BY:

landerbadi

Código pho não executa em banco de dados grande

Recommended Posts

Tenho uma tabela chamada "item" com os seguintes campos: id, name, active. Nela tem cadastrado vários itens. 

No campo "active" eu coloco a letra "S" para informar que este item está ativo no sistema. Por exemplo:

1, casa, S
2, mesa, S
3, cama, S
4, moto S
5, rádio

O quinto registro "radio" não está ativo no sistema pois não tem um "S" no campo active.

E outra tabela chamada "product" com os seguintes campos (id, name) com os seguintes registros:
1, Produto A
2, Produto B
3, Produto C

E uma terceira tabela chamada "product_item" com os seguintes campos (productID, itemID). No campo productID eu coloco o id de um produto da tabela "product" e no campo "itemID" eu coloco o id do produto da tabela "item". Exemplo:

1, 1
1, 3
1, 4
2, 3
2, 4
Sendo assim o produto A da tabela 'product" comtem os itens casa, cama e moto.

Eu preciso fazer uma busca  da seguinte maneira:

Eu escolho um registro da tabela "item", por exemplo "casa". Preciso fazer com que o php me liste todos os registros da tabela "product" que contenham a palavra "casa" e que os demais itens estejam ativos no siste. Ou seja, que contenham um "S" no campo "active"

Eu consegui fazer isso da seguinte maneira:
SELECT P.id, P.name, GROUP_CONCAT(I.name ORDER BY I.name) AS items
FROM product P
JOIN product_item PI ON P.id = PI.productID
JOIN item I ON I.id = PI.itemID AND I.active = 'S'
WHERE P.id NOT IN (
    SELECT PI.productID
    FROM product_item PI
    JOIN item I ON I.id = PI.itemID
    WHERE I.active IS NULL
)
AND P.id IN (
    SELECT PI.productID
    FROM product_item PI
    JOIN item I ON I.id = PI.itemID
    WHERE I.name = 'mesa'
)
GROUP BY P.id, P.name;

O problema que eu estou tendo é o seguinte:

Quando eu jogo este código para o banco de dados onde eu já tenho os registros cadastrado o php fica lendo uma eternidade e não lista os produtos.

 

Usando código no banco de dados que eu fiz para testes ele funciona perfeitamente pois nele tem poucos registros.

 

No banco de dados principal a tabela "item" tem 11.196 registros. A tabela "product" tem 88.214 registros e a tabela "product_item" tem 518.378 registros. 

 

Eu acredito que, devido o banco de dados ser muito grande, ele não consegue listar.

 

Alguém sabe de algum meio de resolver isso?

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Reescreva sua consulta para minimizar o número de operações e junções complexas. Vou fornecer uma versão otimizada da sua consulta:

 

SELECT 
    P.id, 
    P.name, 
    GROUP_CONCAT(I.name ORDER BY I.name) AS items
FROM 
    product P
JOIN 
    product_item PI ON P.id = PI.productID
JOIN 
    item I ON I.id = PI.itemID
WHERE 
    P.id IN (
        SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE I.name = 'casa'
    )
    AND P.id NOT IN (
        SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE I.active IS NULL OR I.active != 'S'
    )
GROUP BY 
    P.id, P.name;

utilização de subconsultas pode ser custosa, especialmente em grandes bancos de dados. Tente minimizar subconsultas complexas. Vou tentar reescrever a consulta para evitar subconsultas:

 

SELECT 
    P.id, 
    P.name, 
    GROUP_CONCAT(I.name ORDER BY I.name) AS items
FROM 
    product P
JOIN 
    product_item PI1 ON P.id = PI1.productID
JOIN 
    item I1 ON I1.id = PI1.itemID
WHERE 
    I1.name = 'casa'
    AND NOT EXISTS (
        SELECT 1
        FROM product_item PI2
        JOIN item I2 ON I2.id = PI2.itemID
        WHERE 
            PI2.productID = P.id
            AND (I2.active IS NULL OR I2.active != 'S')
    )
GROUP BY 
    P.id, P.name;

Execute comandos de análise de índices para garantir que o banco de dados está utilizando os índices de forma eficiente:

 

ANALYZE TABLE item;
ANALYZE TABLE product;
ANALYZE TABLE product_item;

A principal ideia é reduzir a complexidade da consulta e garantir que os índices adequados estão sendo utilizados pelo banco de dados. Além disso, certifique-se de testar cada otimização individualmente para verificar se há melhorias no desempenho.

Compartilhar este post


Link para o post
Compartilhar em outros sites
19 horas atrás, Jack Oliveira disse:

Reescreva sua consulta para minimizar o número de operações e junções complexas. Vou fornecer uma versão otimizada da sua consulta:

 


SELECT 
    P.id, 
    P.name, 
    GROUP_CONCAT(I.name ORDER BY I.name) AS items
FROM 
    product P
JOIN 
    product_item PI ON P.id = PI.productID
JOIN 
    item I ON I.id = PI.itemID
WHERE 
    P.id IN (
        SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE I.name = 'casa'
    )
    AND P.id NOT IN (
        SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE I.active IS NULL OR I.active != 'S'
    )
GROUP BY 
    P.id, P.name;

utilização de subconsultas pode ser custosa, especialmente em grandes bancos de dados. Tente minimizar subconsultas complexas. Vou tentar reescrever a consulta para evitar subconsultas:

 


SELECT 
    P.id, 
    P.name, 
    GROUP_CONCAT(I.name ORDER BY I.name) AS items
FROM 
    product P
JOIN 
    product_item PI1 ON P.id = PI1.productID
JOIN 
    item I1 ON I1.id = PI1.itemID
WHERE 
    I1.name = 'casa'
    AND NOT EXISTS (
        SELECT 1
        FROM product_item PI2
        JOIN item I2 ON I2.id = PI2.itemID
        WHERE 
            PI2.productID = P.id
            AND (I2.active IS NULL OR I2.active != 'S')
    )
GROUP BY 
    P.id, P.name;

Execute comandos de análise de índices para garantir que o banco de dados está utilizando os índices de forma eficiente:

 


ANALYZE TABLE item;
ANALYZE TABLE product;
ANALYZE TABLE product_item;

A principal ideia é reduzir a complexidade da consulta e garantir que os índices adequados estão sendo utilizados pelo banco de dados. Além disso, certifique-se de testar cada otimização individualmente para verificar se há melhorias no desempenho.

Muito obrigado. Testei aqui e funcionou. Demora cerca de 30 segundos para fazer a listagem mais isso não incomoda.

 

Estou com uma outra dúvida. Nesta parte do código:

SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE I.name = 'casa'

Ele busca pela palavra "casa". Tem como fazer com que ele liste também um outro item? Por exemplo: Listar todos os registros que contenham o item "casa" e também os registros que contenham o item "apartamento"?

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Se os nomes dos itens forem exatamente "casa" e "apartamento" pode usar IN

SELECT PI.productID
FROM product_item PI
JOIN item I ON I.id = PI.itemID
WHERE I.name IN ('casa', 'apartamento')

Com php

 

<?php
// Configuração da conexão
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";

// Cria a conexão
$conn = new mysqli($servername, $username, $password, $dbname);

// Verifica a conexão
if ($conn->connect_error) {
    die("Falha na conexão: " . $conn->connect_error);
}

// Define os itens que você deseja buscar
$items = ['casa', 'apartamento'];

// Cria a consulta
$sql = "SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE I.name IN ('" . implode("','", array_map([$conn, 'real_escape_string'], $items)) . "')";

// Executa a consulta
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    // Saída dos dados de cada linha
    while ($row = $result->fetch_assoc()) {
        echo "productID: " . $row["productID"]. "<br>";
    }
} else {
    echo "0 resultados";
}

// Fecha a conexão
$conn->close();
?>

 

Se você precisar buscar por correspondências parciais, como "casa%" ou "apartamento%":

 

Pode usar OR com Like

 

SELECT PI.productID
FROM product_item PI
JOIN item I ON I.id = PI.itemID
WHERE I.name LIKE 'casa%' OR I.name LIKE 'apartamento%'

Php

 

<?php
// Configuração da conexão
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";

// Cria a conexão
$conn = new mysqli($servername, $username, $password, $dbname);

// Verifica a conexão
if ($conn->connect_error) {
    die("Falha na conexão: " . $conn->connect_error);
}

// Define os itens que você deseja buscar
$items = ['casa', 'apartamento'];

// Cria a consulta
$sql = "SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE ";
$whereClauses = [];
foreach ($items as $item) {
    $escapedItem = $conn->real_escape_string($item);
    $whereClauses[] = "I.name LIKE '%$escapedItem%'";
}
$sql .= implode(' OR ', $whereClauses);

// Executa a consulta
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    // Saída dos dados de cada linha
    while ($row = $result->fetch_assoc()) {
        echo "productID: " . $row["productID"]. "<br>";
    }
} else {
    echo "0 resultados";
}

// Fecha a conexão
$conn->close();
?>

 

Agora se você estiver buscando pelos nomes exatos e preferir a sintaxe com OR

 

SELECT PI.productID
FROM product_item PI
JOIN item I ON I.id = PI.itemID
WHERE I.name = 'casa' OR I.name = 'apartamento'
<?php
// Configuração da conexão
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";

// Cria a conexão
$conn = new mysqli($servername, $username, $password, $dbname);

// Verifica a conexão
if ($conn->connect_error) {
    die("Falha na conexão: " . $conn->connect_error);
}

// Define os itens que você deseja buscar
$items = ['casa', 'apartamento'];

// Cria a consulta
$sql = "SELECT PI.productID
        FROM product_item PI
        JOIN item I ON I.id = PI.itemID
        WHERE ";
$whereClauses = [];
foreach ($items as $item) {
    $escapedItem = $conn->real_escape_string($item);
    $whereClauses[] = "I.name = '$escapedItem'";
}
$sql .= implode(' OR ', $whereClauses);

// Executa a consulta
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    // Saída dos dados de cada linha
    while ($row = $result->fetch_assoc()) {
        echo "productID: " . $row["productID"]. "<br>";
    }
} else {
    echo "0 resultados";
}

// Fecha a conexão
$conn->close();
?>

 

 

Se você precisar de correspondências exatas, utilize IN ou OR com igualdade. Se precisar de correspondências parciais, utilize LIKE com OR.

 

 

O php é só uma base de como poderia esta fazendo blz..

 

Ajuste a sua maneira do seu projeto

 

Compartilhar este post


Link para o post
Compartilhar em outros sites
1 hora atrás, landerbadi disse:

Muito obrigado. Testei aqui e funcionou. Demora cerca de 30 segundos para fazer a listagem mais isso não incomoda

otimizar sua consulta e melhorar a performance, a ideia principal é evitar subconsultas complexas e garantir que os índices corretos estão sendo utilizados.

 

SELECT 
    P.id, 
    P.name, 
    GROUP_CONCAT(I1.name ORDER BY I1.name) AS items
FROM 
    product P
JOIN 
    product_item PI1 ON P.id = PI1.productID
JOIN 
    item I1 ON I1.id = PI1.itemID
LEFT JOIN 
    (SELECT PI2.productID
     FROM product_item PI2
     JOIN item I2 ON I2.id = PI2.itemID
     WHERE I2.active IS NULL OR I2.active != 'S'
     GROUP BY PI2.productID) AS InactiveItems ON P.id = InactiveItems.productID
WHERE 
    I1.name = 'casa'
    AND InactiveItems.productID IS NULL
GROUP BY 
    P.id, P.name;

os índices apropriados estão configurados para as tabelas envolvidas. Os seguintes índices são recomendados:

 

CREATE INDEX idx_product_item_productID ON product_item(productID);
CREATE INDEX idx_product_item_itemID ON product_item(itemID);
CREATE INDEX idx_item_id ON item(id);
CREATE INDEX idx_item_name ON item(name);
CREATE INDEX idx_item_active ON item(active);

Php

 

<?php
// Configuração da conexão
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";

// Cria a conexão
$conn = new mysqli($servername, $username, $password, $dbname);

// Verifica a conexão
if ($conn->connect_error) {
    die("Falha na conexão: " . $conn->connect_error);
}

// Cria a consulta
$sql = "
SELECT 
    P.id, 
    P.name, 
    GROUP_CONCAT(I1.name ORDER BY I1.name) AS items
FROM 
    product P
JOIN 
    product_item PI1 ON P.id = PI1.productID
JOIN 
    item I1 ON I1.id = PI1.itemID
LEFT JOIN 
    (SELECT PI2.productID
     FROM product_item PI2
     JOIN item I2 ON I2.id = PI2.itemID
     WHERE I2.active IS NULL OR I2.active != 'S'
     GROUP BY PI2.productID) AS InactiveItems ON P.id = InactiveItems.productID
WHERE 
    I1.name = 'casa'
    AND InactiveItems.productID IS NULL
GROUP BY 
    P.id, P.name;
";

// Executa a consulta
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    // Saída dos dados de cada linha
    while ($row = $result->fetch_assoc()) {
        echo "ID: " . $row["id"] . " - Nome: " . $row["name"] . " - Itens: " . $row["items"] . "<br>";
    }
} else {
    echo "0 resultados";
}

// Fecha a conexão
$conn->close();
?>

Veja se sql assim ajudar melhor o tempo da consulta 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora

  • Conteúdo Similar

    • Por luiz monteiro
      Olá, tudo bem?
       
      Estou melhorando meu conhecimento em php e mysql e, me deparei com o seguinte. A tabela da base de dados tem um campo do tipo varchar(8) o qual armazena números. Eu não posso alterar o tipo desse campo. O que preciso é fazer um select para retornar o números que contenham zeros a direita ou a esquerda.
      O que tentei até agora
       
      Ex1
      $busca = $conexao->prepare("select campo form tabela where (campo = :campo) ");
      $busca->bindParam('campo', $_REQUEST['campo_form']);
       
      Se a direita da string $_REQUEST['campo_form'] termina ou inicia com zero ou zeros, a busca retorna vazio.
      Inseri dados numéricos, da seguinte maneira para testar: 01234567;  12345670: 12345678: 12340000... entre outros nessa coluna. Todos os valores que não terminam ou não iniciam com zero ou zeros, o select funciona.
       
       
      Ex2
      $busca = $conexao->prepare("select campo form tabela where (campo = 0340000) ");
      Esse número está cadastrado, mas não retorna.
       
      Ex3
      $busca = $conexao->prepare("select campo form tabela where (campo = '02340001' ) ");
      Esse número está cadastrado, mas não retorna.
       
       
      Ex4
      $busca = $conexao->prepare("select campo form tabela where (campo like 2340000) ");
      Esse número está cadastrado, mas não retorna.
       
      Ex5
      $busca = $conexao->prepare("select campo form tabela where (campo like '12340000') ");
      Esse número está cadastrado, mas não retorna.
       
      Ex6
      $busca = $conexao->prepare("select campo form tabela where (campo like '"12340000"' ) ");
      Esse número está cadastrado, mas não retorna.
       
       
      Ex7
      $busca = $conexao->prepare("select campo form tabela where (campo like :campo) ");
      $busca->bindParam('campo', $_REQUEST['campo_form'])
      Não retorna dados.
       
      O  $_REQUEST['campo_form'] é envio via AJAX de um formulário. 
      Usei o gettype para verificar o post, e ele retorna string.
      Fiz uma busca com número 12345678 para verificar o que o select retorna, e também retrona como string.
       
      Esse tipo de varchar foi usado porque os números que serão gravados nesse campo,  terão zeros a direita ou na esquerda. Os tipos number do mysql não gravam zeros, então estou usando esse. O problema é a busca.
      Agradeço desde já.
       
       
    • Por daemon
      Boa tarde,
       
      Eu tenho uma rotina que faz uma leitura do arquivo .xml de vários sites.

      Eu consigo pegar o tópico e a descrição, e mostrar a imagem que esta na pagina do link.
      Para isso utilizo esta função:
      function getPreviewImage($url) { // Obter o conteúdo da página $html = file_get_contents($url); // Criar um novo objeto DOMDocument $doc = new DOMDocument(); @$doc->loadHTML($html); // Procurar pela tag meta og:image $tags = $doc->getElementsByTagName('meta'); foreach ($tags as $tag) { if ($tag->getAttribute('property') == 'og:image') { return $tag->getAttribute('content'); } } // Se não encontrar og:image, procurar pela primeira imagem na página $tags = $doc->getElementsByTagName('img'); if ($tags->length > 0) { return $tags->item(0)->getAttribute('src'); } // Se não encontrar nenhuma imagem, retornar null return null; } // Uso: $url = "https://example.com/article"; $imageUrl = getPreviewImage($url); if ($imageUrl) { echo "<img src='$imageUrl' alt='Preview'>"; } else { echo "Nenhuma imagem encontrada"; }  
      Mas estou com um problema, esta funcão funciona quando coloco em uma pagina de teste.php. Preciso mostrar em uma página inicial diversas fotos de todos os links. (No caso acima só funciona 1).
    • Por violin101
      Caros amigos, saudações.
       
      Por favor, me permita tirar uma dúvida com os amigos.

      Tenho um Formulário onde o Usuário digita todos os Dados necessários.

      Minha dúvida:
      --> como faço após o usuário digitar os dados e salvar, o Sistema chamar uma Modal ou mensagem perguntando se deseja imprimir agora ?

      Grato,
       
      Cesar
    • Por Carcleo
      Tenho uma abela de usuarios e uma tabela de administradores e clientes.
      Gostaria de uma ajuda para implementar um cadastro
       
      users -> name, login, passord (pronta) admins -> user_id, registratiom, etc.. client -> user_id, registratiom, etc...
      Queria ajuda para extender de user as classes Admin e Client
      Olhem como estáAdmin
      <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Admin extends User {     use HasFactory;            protected $fillable = [         'name',         'email',         'password',         'registration'     ];      private string $registration;     public function create(         string $name,          string $email,          string $password,         string $registration     )     {         //parent::create(['name'=>$name, 'email'=>$email, 'password'=>$password]);         parent::$name = $name;         parent::$email = $email;         parent::$password = $password;         $this->registration = $registration;     } } User
      <?php namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Relations\BelongsToMany; class User extends Authenticatable {     /** @use HasFactory<\Database\Factories\UserFactory> */     use HasFactory, Notifiable;     static string $name;     static string $email;     static string $password;     /**      * The attributes that are mass assignable.      *      * @var list<string>      */     protected $fillable = [         'name',         'email',         'password',     ];          /**      * The attributes that should be hidden for serialization.      *      * @var list<string>      */     protected $hidden = [         'remember_token',     ];     /**      * Get the attributes that should be cast.      *      * @return array<string, string>      */     protected function casts(): array     {         return [             'email_verified_at' => 'datetime',             'password' => 'hashed',         ];     }          public function roles() : BelongsToMany {         return $this->belongsToMany(Role::class);     }       public function hasHole(Array $roleName): bool     {                 foreach ($this->roles as $role) {             if ($role->name === $roleName) {                 return true;             }         }         return false;     }         public function hasHoles(Array $rolesName): bool     {                 foreach ($this->roles as $role) {             foreach ($rolesName as $rolee) {             if ($role->name === $rolee) {                 return true;             }          }         }         return false;     }         public function hasAbility(string $ability): bool     {         foreach ($this->roles as $role) {             if ($role->abilities->contains('name', $ability)) {                 return true;             }         }         return false;     }     } Como gravar um Admin na tabela admins sendo que ele é um User por extensão?
      Tentei assim mas é claro que está errado...
      public function store(Request $request, Admin $adminModel) {         $dados = $request->validate([             "name" => "required",             "email" => "required|email",             "password" => "required",             "registration" => "required"         ]);         $dados["password"] =  Hash::make($dados["password"]);                  $admin = Admin::where("registration",  $dados["registration"])->first();                  if ($admin)              return                    redirect()->route("admin.new")                             ->withErrors([                                 'fail' => 'Administrador já cadastrados<br>, favor verificar!'                   ]);                            $newAdmin = $adminModel->create(                                    $dados['name'],                                    $dados['email'],                                    $dados['password'],                                    $dados['registration']                                 );         dd($newAdmin);         $adminModel->save();         //$adminModel::create($admin);                  return redirect()->route("admin.new")->with("success",'Cadastrado com sucesso');     }  
×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.