Ir para conteúdo
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 violin101
      Caros amigos, saudações.
       
      Humildemente peço desculpa por postar uma dúvida que tenho.

      Preciso salvar no MySql, os seguinte Registro:

      1 - Principal
      ====> minha dúvida começa aqui
      ==========> como faço para o Sistema Contar Automaticamente o que estiver despois do 1.____?
      1.01 - Matriz
      1.01.0001 - Estoque
      1.01.0002 - Oficina
      etc

      2 - Secundário
      2.01 - Loja_1
      2.01.0001 - Caixa
      2.01.0002 - Recepção
      etc
       
      Resumindo seria como se fosse um Cadastro de PLANO de CONTAS CONTÁBEIL.

      Grato,


      Cesar









       
    • Por violin101
      Caros amigos, saudações.

      Por favor, me perdoa em recorrer a orientação dos amigos.

      Preciso fazer um Relatório onde o usuário pode Gerar uma Lista com prazo para vencimento de: 15 / 20/ 30 dias da data atual.

      Tem como montar uma SQL para o sistema fazer uma busca no MySql por período ou dias próximo ao vencimento ?

      Tentei fazer assim, mas o SQL me traz tudo:
      $query = "SELECT faturamento.*, DATE_ADD(faturamento.dataVencimento, INTERVAL 30 DAY), fornecedor.* FROM faturamento INNER JOIN fornecedor ON fornecedor.idfornecedor = faturamento.id_fornecedor WHERE faturamento.statusFatur = 1 ORDER BY faturamento.idFaturamento $ordenar ";  
      Grato,
       
      Cesar
       
       
       
       
    • Por violin101
      Caros amigos, saudações
       
      Por favor, me perdoa em recorrer a orientação dos amigos, tenho uma dúvida.
       
      Gostaria de uma rotina onde o Sistema possa acusar para o usuário antes dos 30 dias, grifar na Tabela o aviso de vencimento próximo, por exemplo:
       
      Data Atual: 15/11/2024
                                           Vencimento
      Fornecedor.....................Data.....................Valor
      Fornecedor_1...........01/12/2024..........R$ 120,00 <== grifar a linha de Laranja
      Fornecedor_1...........01/01/2025..........R$ 130,00
      Fornecedor_2...........15/12/2024..........R$ 200,00 <== grifar a linha de Amarelo
      Fornecedor_2...........15/01/2025..........R$ 230,00
      Fornecedor_3...........20/12/2024..........R$ 150,00
       
      Alguém tem alguma dica ou leitura sobre este assunto ?

      Grato,
       
      Cesar
    • Por violin101
      Caros amigos, saudações.

      Por favor, me perdoa em recorrer a ajuda dos amigos, mas preciso entender uma processo que não estou conseguindo sucesso.

      Como mencionado no Título estou escrevendo um Sistema Web para Gerenciamento de Empresa.
       
      Minha dúvida, que preciso muito entender:
      - preciso agora escrever a Rotina para Emissão de NFe e essa parte não estou conseguindo.
       
      tenho assistido alguns vídeos e leituras, mas não estou conseguindo sucesso, já fiz toda as importações das LIB da NFePhp conforme orientação.

      Preciso de ajuda.

      Algum dos amigos tem conhecimento de algum passo-a-passo explicando a criação dessa rotina ?

      tenho visto alguns vídeos com LARAVEL, mas quando tento utilizar e converter para PHP+Codeiginter, dá uma fila de erros que não entendo, mesmo informando as lib necessárias.

      Alguns do amigo tem algum vídeo, leitura explicando essa parte ?

      Grato,

      Cesar.
    • Por violin101
      Caros amigos, saudações.

      Por favor, me perdoa em recorrer ao auxílio dos amigos, mas preciso entender e resolver um problema.
       
      Tenho uma Rotina que o usuário seleciona os produtos que deseja para requerer ao setor responsável.
       
      O usuário escolhe um produto qualquer e Clicla em um button para incluir a lista.

      O problema que estou enfrentando é que após escolher o produto e teclar ENTER o Sistema já salva no BD.
       
      Gostaria de criar uma Tecla de Atalho, para quando incluir/escolher o produto na lista, o usuário tecla como exemplo:
      ALT+A  para agregar a lista
      ALT+S para salvar a lista de itens desejados.

      Assim, quando teclar enter, o sistema não dispara o GRAVAR na Base de Dados.

      Grato,

      Cesar
       
       
       
×

Informação importante

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