emotta Posted March 25, 2020 Report Share Posted March 25, 2020 Pessoal, a pergunta é para quem manja de SQL (mais especificamente SQL SERVER) Tenho uma rotina que fica esperando que determinado campo seja setado como "1". O que estou fazendo hoje é um WHILE e dentro do while fico verificando If FILE->STATUS = "1" e se a condição for .T. ele processa. O que acontece é que isso sobrecarrega o banco de dados, coloquei uma espera de 1s então a cada minuto ele manda para o banco de dados 60 transações verificando o campo. Eu gostaria de resolver isso enviando um SELECT para o banco de dados e que esse SELECT somente me retornasse quando tivesse um registro com STATUS = '1'. Enquanto nenhum registro fosse setado como '1' ele ficaria na espera. Alguem tem uma solução para este caso? PS: Aumentar o tempo no laço nao vai adiantar pois eu preciso que assim que um registro tiver o status setado como "1" ele precisa iniciar o processo. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 criando um outra tabela relacionada com a tabela atual com o mesmo campo STATUS... quando essa tabela receber registro vc pegaria o status e fazia o processo (select) com o ID da tabela nova apagando o registro depois do processo... verificando sempre (TIME) se tabela nova tem registro para fazer o select novamente Acredito q vc não entendeu... Fazer o esquema todo eu já fiz e funciona perfeitamente... O que desejo melhorar agora é a quantidade de requisições q ele faz ao banco de dados. Cada vez a eu verifico o campo é uma requisição ao banco. Se eu faço uma vez por segundo sao 60 requisições. Eu poderia aumentar o tempo de checagem mas aí perco agilidade. Eu gostaria de fazer o seguinte: enviar um select ao banco de dados e ele me retorna só qdo tiver algum dado ou qdo der um tempo de tineout. Se eu conseguir isso o meu programa só vai executar uma transação para o sql. Enfim sua sugestão não funciona oq eu teria q ficar monitorando do mesmo jeito. Mais uma coisa: a solução para o caso tem q ser no sql, não pode ser em dbf, arquivo de semáforo ou QQ outra coisa q não seja via sql. É bem difícil explicar aqui o motivo. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 Acho q descobri como fazer Amanhã vou estudar este comando https://docs.microsoft.com/pt-br/sql/t-sql/statements/receive-transact-sql Quote Link to comment Share on other sites More sharing options...
Eroni Posted March 26, 2020 Report Share Posted March 26, 2020 Bom dia. Tenho uma rotina parecida, em que o sistema fica monitorando o banco de dados para verificar se é necessário desconectar o usuario. Criei um timer que é visivel na aplicação inteira. ( Minha janela principal é um objeto publico.. ) e em um determinado intervalo de tempo o select é executado. Se não me engano é a cada 30 segundos que o select é executado, sendo que o retorno é sempre de 1 registro. Espero ter ajudado, qualquer coisa estamos ao dispor. Abraço. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 Eroni, estou fazendo exatamente isso, com um temporizador tb... só que no meu caso é de 1s em 1s pois quando cai o registro para processar esse processamento precisa responder rápido. O que você sugeriu cai no mesmo problema, de 30s em 30s ele precisa fazer uma requisição ao SQL para monitorar se tem algo a processar. Em resumo: Não posso aumentar o tempo para 30s pois pode acontecer do registro cair e demorar 30s para que a aplicação perceba esse registro e o processe. Mas obrigado pela tentativa, vou testar o link acima que encontrei ontem vamos ver. Se eu conseguir posto aqui a solução. Quote Link to comment Share on other sites More sharing options...
Eroni Posted March 26, 2020 Report Share Posted March 26, 2020 Olá, por acaso o processamento é demorado, são muitos registros? Se sim, poderia interromper o timer e só verificar novamente após a conclusão do processo, isso iria diminuir as requisições ao banco. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 o problema não é o tempo que ele leva pra processar... o problema que desejo resolver é a checagem constante na tabela verificando se tem algo. A solução seria aumentar o tempo que hoje de de 1s em 1s para 60s em 60s (por exemplo) mas se aumentar esse timer pode cair um registro para ser processado e ter uma demora de 60s para o programa perceber. Isso inviabilizaria o processo pois a resposta deve ser rápida. Hoje o codigo é assim: While .t. If SRV->SRV_STATUS = "1" Processa(SRV->SRV_CODIGO) Endif ThreadSleep(1000) EndDo o problema é que ele fica chegando de 1s em 1s o registro e quando o campo STATUS fica como 1 ele processa o registro. Enquanto fica "0" ele fica no laço. Em resumo: Tenho que ter uma resposta rápida quando o STATUS for setado como 1 e não quero que o sistema fique requisitando ao banco de dados verificando se o STATUS ficou 1. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 Vejo que a solução para o meu caso é essa, mas ainda não consegui decifrar como funciona esse BEGIN CONVERSATION https://docs.microsoft.com/pt-br/sql/t-sql/statements/begin-conversation-timer-transact-sql?view=sql-server-2017 PS: Estou usando o SQL SERVER 2017 Quote Link to comment Share on other sites More sharing options...
Eroni Posted March 26, 2020 Report Share Posted March 26, 2020 Neste caso, acho que deve implementar a store procedure descrita no link, o Sqlserver deve suportar este recurso. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 Exatamente, estou estudando como funciona isso que não é uma stored procedure normal, é um recurso diferente...estou estudando isso Caso nao consiga vou implementar uma stored procedure convencional. A checagem de 1s em 1s continurá mas pelo menos não terá transito na rede Quote Link to comment Share on other sites More sharing options...
ADutheil Posted March 26, 2020 Report Share Posted March 26, 2020 Eu tentaria com um TRIGGER AFTER UPDATE/AFTER CREATE Quote Link to comment Share on other sites More sharing options...
alex2002 Posted March 26, 2020 Report Share Posted March 26, 2020 Emotta, o Trigger resolve o seu problema. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 trigger não resolve, eu continuo tendo que continuar verificando a coluna se ela mudou o status.... Quote Link to comment Share on other sites More sharing options...
vagner Posted March 26, 2020 Report Share Posted March 26, 2020 Motta, blz ? Creio que o Schedule possa resolver o seu problema https://docs.microsoft.com/pt-br/sql/ssms/agent/create-a-schedule?view=sql-server-ver15 -- creates a schedule named RunOnce. -- The schedule runs one time, at 23:30 on the day that the schedule is created. USE msdb ; GO EXEC dbo.sp_add_schedule @schedule_name = N'RunOnce', @freq_type = 1, @active_start_time = 233000 ; GO Quote Link to comment Share on other sites More sharing options...
emotta Posted March 26, 2020 Author Report Share Posted March 26, 2020 Vagner pelo que entendi ele vai executar as 23:30h certo? Não resolvi pq se a tabela tiver o status setado como '1' só vai processar as 23:30h Teria que ser um SELECT que só me retorna quando tem algum registro ou se passa o timeout vagner 1 Quote Link to comment Share on other sites More sharing options...
Valdir Posted March 26, 2020 Report Share Posted March 26, 2020 Perdoem a minha "Santa Ignorância"... Porque não setar uma variável ao invés do dB ? Eu faço isso usando Timer para avaliar o valor de uma variável pública a cada segundo. Sempre que algum usuário acessa determinado Campo e o Valida, altero o valor desta variável para executar outra rotina. Ao final desta rotina. retorno o valor anterior desta varável. Não sei se é isso, porém no meu caso funfa certinho. Abraços. Quote Link to comment Share on other sites More sharing options...
ADutheil Posted March 26, 2020 Report Share Posted March 26, 2020 O que não estou entendendo é quem/que seta o valor para "1". Se for teu próprio programa porque não faz o tal SELECT quando faz o update de tua tabela para "1"? Quote Link to comment Share on other sites More sharing options...
marcioe Posted March 27, 2020 Report Share Posted March 27, 2020 O que não estou entendendo é quem/que seta o valor para "1". Se for teu próprio programa porque não faz o tal SELECT quando faz o update de tua tabela para "1"? Pelo que entendi ele monitora um determinado status, poderia ser S/N, ETC... TIPO QUE FAÇO PARA VER SE CHEGOU NOVOS PEDIDOS PELA AUTOMAÇAO DE FORÇA DE VENDAS Quote Link to comment Share on other sites More sharing options...
vagner Posted March 27, 2020 Report Share Posted March 27, 2020 Vagner pelo que entendi ele vai executar as 23:30h certo? Não resolvi pq se a tabela tiver o status setado como '1' só vai processar as 23:30h Teria que ser um SELECT que só me retorna quando tem algum registro ou se passa o timeout Motta, não conheço a fundo o SQL, mas se não me engano você pode colocar no start a hora que vai começar o funcionamento e depois existem outros parâmetros onde você pode ficar monitorando como no caso do timer, mas creio que isso vá fazer também dar um consumo no banco, porém de qualquer maneira ele teria que ficar olhando o banco para ver através de uma function que você poderia fazer dentro do próprio banco junto ao schedule, não conheço muito o trigger porém se você setar para esse campo será que não daria ? qualquer mudança rodaria uma function ou um select. É somente uma ideia Quote Link to comment Share on other sites More sharing options...
emotta Posted March 27, 2020 Author Report Share Posted March 27, 2020 Pessoal agradeço muito todas as sugestões e idéias, infelizmente nenhuma foi possivel colocar em prática, muito mais pq eu não consegui explicar exatamente minha necessidade já que é muito complicado explicar o que preciso escrevendo, é uma situação bem inusitada. Vou tentar explicar de uma outra maneira e dps vou dizer o que eu fiz e resolveu: - Imagine que temos um cadastro de cliente e a cada cliente novo cadastrado, pode ser por qualquer terminal, temos que enviar um email de boas vindas. Então quando algum terminal cadastrar este cliente temos um campo chamado BOASVINDAS = "N". - No servidor eu tenho um programa xHarbour sendo executando em background que fica dando select na tabela de clientes e no where BOASVINDAS = "N". Sempre que esse SELECT retornar algum cliente eu pego cada cliente e envio um email de boas vindas. - É preciso ser muito rápido, ou seja, assim que o cleinte é cadastrado em algum terminal o programa que está rodando no servidor tem que já mandar este email. Então o select que este programa faz no banco é de 1s em 1s pois sendo assim o tempo máximo para que o serviço envie o email ao novo cliente será de 1s. - Fazendo este select de 1s em 1s eu envio 60 transações SQL ao banco por minuto. Considerando que por dia são poucos clientes cadastrados eu considero isso um desperdicio de processamento. - Existem N possibilidades alternativas como por exemplo fazer o disparo do email por um JOB no SQL, fazer o envio do email no prórprio cadastro do cliente e N outras coisas que não vou explicar os motivos mas não poderei aplicar. - Tem que ser desta forma ou seja, o programa rodando no servidor em background e que ele capture este novo cliente rapidamente, no máximo em 1s. Porem preciso que não se tenha este desperdicio de transações por minuto. COMO EU RESOLVI: - O meu programa em background executa uma STORED PROCEDURE e essa procedure retorna uma lista de codigos de clientes novos (BOAS VINDAS = "N") o meu programa envia o email pra cada novo cliente e seta nelas o BOAS VINDAS = "S" - A stored procedure fica executando o select buscando clientes BOAS VINDAS = "N" quando tem algo ele retorna os dados para a aplicação e enquanto não tem ele fica em um while dentro da procedure. - Fiz um contador para que quando der 1 minuto ele retorne vazio para a aplicação. Preciso fazer isso para que a aplicação não fica travada. - Desta forma tenho apenas 1 requisição ao banco por minuto (STORED PROCEDURE). ** a situação acima foi apenas para explicar minha necessidade. O que estou precisando não é exatamente enviar email de boas vindas a novas clientes mas o exemplo acima ilucida exatamente o que preciso. Exemplo da procedure: CREATE OR ALTER PROCEDURE BuscaNovos AS BEGIN SET NOCOUNT ON; DECLARE @Contador INT SET @Contador = 1 WHILE (SELECT COUNT(*) FROM TAB_CLI WHERE BOASVINDAS = 'N') = 0 and @Contador < 60 BEGIN WAITFOR DELAY '00:00:01'; SET @Contador = @Contador + 1 END SELECT * FROM TAB_CLI WHERE BOASVINDAS='N' END Quote Link to comment Share on other sites More sharing options...
alex2002 Posted March 29, 2020 Report Share Posted March 29, 2020 Sinceramente não entendo porque a Trigger não resolveria, sendo que vc pode setar ela, antes, durante e depois dos insertes/deletes/updates. Mas que bom que resolveu então. Quote Link to comment Share on other sites More sharing options...
emotta Posted March 30, 2020 Author Report Share Posted March 30, 2020 Alex, não resolve... Na explicação acima eu explico que o serviço para mandar o "boas vindas" está rodando no servidor e quem cadastra o cliente é uma estação qualquer. Se eu colocar na TRIGGER pra dar o boas vindas quem vai processar é o SQL e eu preciso que quem processe seja o serviço (xHarbour) que fica executando no servidor e esperando cair um cliente novo que ainda não teve o boas vindas enviado. Trigger também foi meu primeiro pensamento mas que descartei logo de cara. Seria bem mais simples fazer por ele mas infelizmente não foi. Mas obrigado pela ajuda, de certa forma as idéias sempre são aproveitadas ! vlwww Quote Link to comment Share on other sites More sharing options...
kapiaba Posted March 30, 2020 Report Share Posted March 30, 2020 Você se refere a isso Emotta? Quote Link to comment Share on other sites More sharing options...
emotta Posted March 30, 2020 Author Report Share Posted March 30, 2020 Você se refere a isso Emotta? Isso mesmo.... Mas o problema não era fazer, isso eu já tinha conseguido desde o inicio, a rotina já funcionava bem. O problema era a quantidade de requisições ao banco de dados por minuto, eram muitas requisições feitas ao SQL desnecessariamente. Então em vez de fazer 1 select por segundo eu passei a executar uma stored procedure que só me retorna quando tive novidade ou quando der o tempo de 1 minuto informando que não teve novidade. Mas a rotina do seu post é bem semelhante porem possivelmente ele faz um desperdício de processamento da mesma forma que eu estava fazendo (como não postou a forma que ele busca novos pedidos só da pra deduzir). O problema não era desenvolver a rotina e sim evitar esse desperdício. vlwww ae kapiaba 1 Quote Link to comment Share on other sites More sharing options...
kapiaba Posted March 30, 2020 Report Share Posted March 30, 2020 ok. Good. Tem também esse post aqui, que parece ser interessante: http://forums.fivetechsupport.com/viewtopic.php?f=3&t=32263&start=45 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.