Mysql: consulta lenta

Forum sobre SQL.

Moderador: Moderadores

cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

Mysql: consulta lenta

Mensagem por cjp »

Você informou que estes minutos podem ser horas ou até mesmo dias. Na query você filtra por uma data. Desta forma, temos um período com data e hora de início e fim. Como é obtido este período? Vem de uma tela onde o usuário informa?
Não é o usuário que informa não. Está determinado no sistema, de acordo com a marca. Se a marca é V, o tempo é de minutos. Se for A, horas. Se estiver em branco, dias. A query é um pouco diferente em cada caso. Postei só o primeiro caso porque, se eu conseguir resolver ele, vou conseguir resolver também os demais.
Aí que está.
A data/hora é pra ter o que NÃO SAI.
Não saem os códigos com movimento naquela data/hora, mas o resto sai tudo.
Sim, a data/hora é justamente para não selecionar os códigos que não tenham registros a partir dessa data/hora.

A ideia é simples (preciso dos códigos que não tenham registro a partir de uma determinada data/hora). A minha execução é que não está simples. E por isso está gerando essa confusão. Certamente deve haver uma solução mais simples que a minha, só não sei qual.

Está pegando somente o código, e colocando em ordem de.... mas se só tem código, como aceita ordem em outros campos?
Tem algum problema em colocar em ordem por outro campo que não esteja na consulta? Um select assim: select codigo from acoes where... order by dtcotacao estaria errado? Acho que não. Já fiz isso sem problema.

Não tem um cadastro de códigos? se não tem, tá misturando cadastro com movimento, o que exige processar tudo só pra pegar a lista de códigos.
Não sei se te entendi bem. Vc quer dizer que eu deveria fazer uma tabela só para cadastrar os códigos e outra só para as cotações? Isso simplificaria a consulta? Como seria?
Inacio de Carvalho Neto
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Mysql: consulta lenta

Mensagem por JoséQuintas »

Crie um índice por código/data
Se o campo for date/time, talvez algo assim

Código: Selecionar todos

SELECT CODIGO, MAX(DTCOTACAO) AS ULTIMA 
FROM ACOES 
GROUP BY CODIGO 
HAVING DTULTIMA < '2021-04-22'
ORDER BY DTULTIMA
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

Mysql: consulta lenta

Mensagem por cjp »

Testei como vc disse, mas está retornando um resultado estranho. Veja as imagens anexas. MNPR3 tem cotação de hoje, mas está retornando a data 2020-05-29.
Anexos
having2.png
having.png
having.png (9.07 KiB) Exibido 9268 vezes
Inacio de Carvalho Neto
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Mysql: consulta lenta

Mensagem por JoséQuintas »

Tente no plano B.
Talvez o HAVING não se aplique nessa situação.

Código: Selecionar todos

SELECT * FROM 
( SELECT CODIGO, MAX(DTCOTACAO) AS ULTIMA 
   FROM ACOES 
   GROUP BY CODIGO ) AS A
WHERE DTULTIMA < '2021-04-22'
ORDER BY DTULTIMA
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Mysql: consulta lenta

Mensagem por alxsts »

Olá!

Vejo a questão como um problema fácil de resolver. Seria uma consulta simples, do tipo:

Código: Selecionar todos

SELECT <colunas>
  FROM <tabela>
 WHERE coluna_data >= data_inicial
   AND coluna_hora >= hora_inicial
   AND coluna_data <= data_final
   AND coluna_hora <= hora_final
ORDER BY <colunas>
O problema é que programação de computadores requer detalhes específicos e as informações que temos são insuficientes e chegam a conta-gotas. Sei que todos sofremos com falta de tempo mas, quanto mais informações detalhadas tivermos, mais rapidamente encontraremos uma solução.
1 - A ideia deste select é pegar na tabela acoes os códigos dos registros que tenham marca=V e hrvisto#91234 e que não tenham tido
nenhum registro nos últimos minutos.

- Não faço a menor idéia do que é hrvisto <> 91234, dá a impressão de que está salvando horário em formato numérico, e se quer
isso específico, também um índice por isso poderia ajudar, dependendo do que significa isso.

- O campo hrvisto é realmente para salvar a hora em formato numérico. Mas neste caso (<>91234) é só um código para excluir
determinados códigos.

--> Está usando hrvisto apenas para teste/exemplo desta query ou isso é necessário na aplicação real?

2 - Na tabela a marca não é sempre V, tem várias; nessa consulta que eu coloquei de exemplo, a marca é V, mas também consulto por
outras marcas, e às vezes por mais de uma ao mesmo tempo, razão pela qual coloquei order by marca desc.

- É assim: meu sistema está a todo momento inserindo registros na tabela, referente a códigos diversos, com data e hora da inserção.
Então, esta consulta precisa retornar os códigos que não tiveram inserção de registros nos últimos minutos (neste caso),
ou nas últimas horas ou nos últimos dias (em consultas semelhantes).

- Não é o usuário que informa não. Está determinado no sistema, de acordo com a marca. Se a marca é V, o tempo é de minutos.
Se for A, horas. Se estiver em branco, dias. A query é um pouco diferente em cada caso. Postei só o primeiro caso porque,
se eu conseguir resolver ele, vou conseguir resolver também os demais.

- O que eu realmente preciso: uma lista dos códigos da tabela que não tiveram cotação registrada nos últimos minutos.

--> É bem contraditorio...
É fácil imaginar as consultas separadamente por minutos ou horas ou dias. É questão de parametrizar a consulta.
Em um momento Você diz "também consulto por outras marcas, e às vezes por mais de uma ao mesmo tempo" e em outro momento diz
"(em consultas semelhantes)". Você tem consultas diferentes para cada caso?
Pergunto porque se criarmos uma consulta parametrizada que recebe os parâmetros Tipo, Quantidade (de minutos, horas ou dias,
conforme o tipo) e Data inicial seria fácil processar e retorner o resultado daquele tipo.
Para mais de um tipo, teria que fazer um UNION ou algo do tipo.
Não sabemos qual a tua necessidade mas, a princípio, parece uma coisa sem sentido consultar a data de criação de um orçamento,
ao mesmo tempo por minutos, horas ou dias...

Outro ponto importante:
quando você diz "minutos (neste caso), ou nas últimas horas ou nos últimos dias (em consultas semelhantes)" está se referindo
à data e hora em que a consulta está sendo executada? Ou seja, vai limitar os registros a uma data inicial e data atual
MENOS alguns minutos, algumas horas ou dias, conforme o tipo?


3 - Pra trazer os códigos não é o group by, é o distinct.
group by é pra somar, o que exige pegar tudo, enquanto distinct já pega um de cada, o que só precisa de um de cada.
-> GROUP BY não é para somar. É para agrupar linhas segundo um critério determinado. Não exige pegar tudo, a menos que não
haja uma cláusula WHERE. Se houver WHERE, vai agrupar apenas o que sobrou do filtro do WHERE. WHERE FILTRA LINHAS.
Não vejo necessidade de DISTINCT nem GROUP BY neste caso.


4 - No teu select interno tem "where compvenda=0"
--> Neste caso, os registros retornados compvenda diferente de zero. Certo?

5 - Aí que está. A data/hora é pra ter o que NÃO SAI. Não saem os códigos com movimento naquela data/hora, mas o resto sai tudo.
--> São parâmetros necessários.


6 - Talvez o HAVING não se aplique nessa situação.
Neste caso realmente não se aplica.
HAVING FILTRA GRUPOS (GRUPOS SÃO OS RESULTADOS OBTIDOS PELO GROUP BY)
Exemplo:

Código: Selecionar todos

-- Determinar números repetidos em uma sequência de números
WITH Numeros(Id, Nome) AS
  (
    VALUES
      (0, 'Zero'), (1, 'Um'), (2, 'Dois'), (3, 'Tres'), (3, 'Tres'), (4, 'Quatro'), (5, 'Cinco'), 
      (5, 'Cinco'), (6, 'Seis'), (7, 'Sete'), (7, 'Sete'), (8, 'Oito'), (9, 'Nove'), (9, 'Nove')
   )
SELECT * FROM Numeros
WHERE Id >= 3 AND Id <= 9  --> Filtra linhas com número entre 3 e 9
GROUP BY Id                --> Agrupa o resultado que sobrou do WHERE
HAVING Count(Id) > 1       --> Filtra os grupos resultantes do GROUP BY pegando apenas os que tem count(Id) > 1
Resultado:

Código: Selecionar todos

#	Id	Nome
1	3	Tres
2	5	Cinco
3	7	Sete
4	9	Nove
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Mysql: consulta lenta

Mensagem por JoséQuintas »

Aquele filtro separado de data/hora não dá certo.

Data >= '2021-03-01' and hora >= '18:00'

Isso não vai pegar nada que tenha horário menor que 18:00 de nenhuma data.
Talvez parecido com isto:

Código: Selecionar todos

DATA BETWEEN a AND B OR ( Data = c and hora between e and f )
Lembrando que pode precisar de CAST( x AS DATE ) para que seja comparada DATE e não DATETIME.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Mysql: consulta lenta

Mensagem por alxsts »

Olá!

Como ele tem o campo da data do orçamento tipo DATE e campo hora tipo varchar ou char, tem que montar a data e hora de início, montar a data final subtraindo minutos, horas ou dias, conforme o tipo, e selecionar os dados. Claro que vai ter que colocar as outras condições no where.

Código: Selecionar todos

  SELECT CAST( CONCAT( CAST( CURDATE() AS VARCHAR(10) ),  --> Trocar "CURDATE()" pelo nome campo da tabela
                       ' ', 
                       LEFT('18:11', 2),
                       ':',
                       RIGHT('18:11',2) 
                     ) AS DATETIME) as Inicio
Resultado = 2021-04-25 18:11:00 (tipo DATETIME)

Tem que criar um índice igual ao select acima.

Outra pergunta: como você acessa o teu banco de dados (ADO, SQL Mix)?
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Mysql: consulta lenta

Mensagem por JoséQuintas »

alxsts escreveu:Outra pergunta: como você acessa o teu banco de dados (ADO, SQL Mix)?
Essa eu posso responder:
Era SQLMIX mas ele tinha muito problema, então sugeri o ADO.
Com ADO resolveu.

Não sei dizer se havia problema no uso de SQLMIX, porque não uso.
Mas com certeza, agora ele procura trazer as coisas prontas do servidor.
Até já usou coisas que eu não sabia que funcionava... já está me ensinando também.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Mysql: consulta lenta

Mensagem por alxsts »

Olá!
Entendi. Não sei se vou conseguir criar um exemplo mas, com ADO fica mais fácil. Nunca mexi com SQL Mix.

Pelo que dá pra deduzir do SQL do primeiro post, o campo de hora já está no formato 99:99. Assim, não precisa do left e right que usei acima. Basta concatenar este campo direto com a data em formato texto, mais um espaço.
[]´s
Alexandre Santos (AlxSts)
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Mysql: consulta lenta

Mensagem por alxsts »

Olá!
Até já usou coisas que eu não sabia que funcionava... já está me ensinando também.
Este é o lado bom do fórum!
[]´s
Alexandre Santos (AlxSts)
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

Mysql: consulta lenta

Mensagem por cjp »

Está usando hrvisto apenas para teste/exemplo desta query ou isso é necessário na aplicação real?
Hrvisto é um campo real da tabela, e é usado na aplicação real. Esta consulta apenas exclui os casos em que o campo hrvisto for igual a 91234 (que é um parâmetro usado para alguns códigos específicos).

É bem contraditorio...
É fácil imaginar as consultas separadamente por minutos ou horas ou dias. É questão de parametrizar a consulta.
Em um momento Você diz "também consulto por outras marcas, e às vezes por mais de uma ao mesmo tempo" e em outro momento diz
"(em consultas semelhantes)". Você tem consultas diferentes para cada caso?
Pergunto porque se criarmos uma consulta parametrizada que recebe os parâmetros Tipo, Quantidade (de minutos, horas ou dias,
conforme o tipo) e Data inicial seria fácil processar e retorner o resultado daquele tipo.
Para mais de um tipo, teria que fazer um UNION ou algo do tipo.
Não sabemos qual a tua necessidade mas, a princípio, parece uma coisa sem sentido consultar a data de criação de um orçamento,
ao mesmo tempo por minutos, horas ou dias...
Veja: são consultas diferentes, feitas em momentos diferentes, separadamente. Portanto, não é o caso de fazer uma só consulta para todas as situações.
Quando a marca é V, a consulta leva em conta minutos; quando é A, horas; quando está em branco, dias.
Neste caso, os registros retornados compvenda diferente de zero. Certo?
Desculpe, mas não te entendi bem.
Compvenda é um campo da tabela, numérico. Nesta consulta, só interessam os registros em que compvenda=0.

Não sei dizer se havia problema no uso de SQLMIX, porque não uso.
Mas com certeza, agora ele procura trazer as coisas prontas do servidor.
Até já usou coisas que eu não sabia que funcionava... já está me ensinando também.
Muita bondade sua. Quem sou eu para ensinar alguém aqui!
A verdade é que eu aprendi o pouco que sei aqui no grupo. Usei inicialmente SQLMIX usando o tutorial do Toledo. Não havia problema no SQLMIX nesta consulta. Mudei para o ADO pela recomendação do Quintas, o que melhorou bastante meu sistema. E sim, procuro trazer as coisas prontas do servidor. Aliás, esta é a razão deste post: tentar melhorar a forma de trazer os dados desta consulta, para que ela dure menos tempo, evitando consultas lentas.
Inacio de Carvalho Neto
Avatar do usuário
Itamar M. Lins Jr.
Administrador
Administrador
Mensagens: 7928
Registrado em: 30 Mai 2007 11:31
Localização: Ilheus Bahia
Curtiu: 1 vez

Mysql: consulta lenta

Mensagem por Itamar M. Lins Jr. »

Olá!
Era SQLMIX mas ele tinha muito problema, então sugeri o ADO.
Quais são os problemas do SQLMIX ?

Saudações,
Itamar M. Lins Jr.
Saudações,
Itamar M. Lins Jr.
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

Mysql: consulta lenta

Mensagem por cjp »

Na verdade não posso afirmar que o problema era propriamente do SQLMIX. Mais provavelmente era problema da minha programação.
O maior problema era ficarem várias conexões abertas, chegando a estourar o limite de 100 conexões do provedor.
Com o ADO não tenho mais esse problema.
Inacio de Carvalho Neto
Avatar do usuário
Itamar M. Lins Jr.
Administrador
Administrador
Mensagens: 7928
Registrado em: 30 Mai 2007 11:31
Localização: Ilheus Bahia
Curtiu: 1 vez

Mysql: consulta lenta

Mensagem por Itamar M. Lins Jr. »

Olá!
ficarem várias conexões abertas,
Não entendi nada, pq abrir vária conexões ?
Basta uma só.

Deveria está conectando,(abrindo) conexão para cada sentença SQL... Só se for isso.

Saudações,
Itamar M. Lins Jr.
Saudações,
Itamar M. Lins Jr.
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

Mysql: consulta lenta

Mensagem por cjp »

Sim, sempre fiz uma conexão para cada query.
A questão é que eu nem sempre conseguia fechar a conexão. Não sei porquê, mas a conexão frequentemente ficava aberta.
Já testei certa vez deixar uma conexão aberta sempre, e usá-la para tudo. Mas comigo isso não funcionou.
Com o ADO, consigo abrir a conexão, executar o que quero, e fechar em seguida, sem problema.
Inacio de Carvalho Neto
Responder