Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Jean Franceschi

Otimizando o Script ASP

Recommended Posts

Fala galerinha ^^

Bem, um assunto interessante e que pode acabar ajudando algumas pessoas aqui do fórum (isso se conseguirmos descobrir se tem como)!

 

Seguinte, vou colocar um afot que pode ocorrer: Tenho uma site com um banco de dados gigante, cerca de 50 mil cadastros em mais de 30 campos em uma mesma tabela. Uma busca simples dentro disso seria razoavelmente rápida, porém, o caso é que cerca de 100 pessoas acessam essa tabela a cada minuto e isso sim gera um gasto gigante no servidor. Então, procurando aqui na internet achei uma matéria boa, mas eu não sei se funciona, falando do uso do comando MaxRecords ao abrir, limitando assim o conteúdo aberto do banco de dados.

 

Porém surge um probleminha, toda vez que é aberta uma tabela no banco de dados pelo script ele gera uma busca e não tem como saber se esta busca será feita encontrando 10 ou 50 ou 100 ou até 1000 registros, então fica complicado usar o MaxRecords e setar ele com um limite de 10 (por exemplo).

 

Então, num flash básico na minha cabeça surgiu a idéia de antes disso, efetuar uma contagem de possíveis resultados pra só então setar o MaxRecords com o resultado encontrado.

 

Vou dar um exemplo:

 

<%
  connstring = "dsn=banco;uid=usuario;pwd=senha"

  Set conn = Server.CreateObject("ADODB.Connection")
      Conn.Open connString
      Set rstContagem = Conn.Execute("SELECT Count(Id) FROM hoteis WHERE dados='dadosimaginários'")
        If rstContagem.EOF Then
          Contagem = 0
        Else
          Contagem = rstContagem(0)
        End If
        rstContagem.Close
      Set rstContagem = Nothing

      sql = "SELECT * FROM hoteis WHERE dados='dadosimaginários' ORDER BY diaria desc"
      Set rstTemp = Server.CreateObject("ADODB.RecordSet")
          rstTemp.MaxRecords = Contagem 'Aqui entraria o número encontrado pela contagem
          rstTemp.Open sql, connstring
          Do while not rstTemp.Eof
            Response.Write(rstTemp("Hotel") & " - " & rstTemp("Diaria"))
          rstTemp.MoveNext
          Loop

'continua e fecha tudo que ta aberto!
%>

Então, usando isso ele abriria somente os dados realmente encontrados com a contagem ao invés de abrir todos os registros e procurar o que falta.

O script eu refiz aqui como exemplo, nem sei se funciona, pode ter erro pois é complicado usar o editor pra fazer isso sem ter erros.

 

Mas a idéia é essa, usando a propriedade Maxrecords a idéia é ele abrir somente aquela quantidade destinada ao invés de abrir todas e então fazer a busca.

Na matéria que eu tinha visto isso otimizaria o script pouco, mas como o exemplo aqui é sobre muitos acessos, este pouco se torna muitos ^^

 

O problema é que na matéria não falava em usar uma rotina pra contar os resultados, falava apenas em usar o Maxrecords com um número X pra limitar a busca no banco de dados e eu fiquei na dúvida se quando eu for fazer uma contagem eu vá acabar abrindo todo ele pra contar e depois abrindo ele só pra mostrar a quantidade certa, isso resultaria no dobro da operação então seria mais simples e mais otimizado se eu nem usar o Maxrecords.

 

Acho que expliquei direito, qualquer coisa me avisem q eu refaço ou vou dizendo o que é que ta faltando pra compreensão de todos.

 

Uma abração,

Jean

Compartilhar este post


Link para o post
Compartilhar em outros sites

possivelmente seu problema seja minimizado ou até mesmo resolvido criando indices no banco de dados. Te digo que, dependendo do banco, não é necessário soluções alternativas no código. Trabalho com tabelas que tem milhares e algumas que tem milhões de registros e as consultas não levam mais que 2 segundos para serem executadas, mas pra isso as tabelas tem que estar bem montadas e bons indices criados.

 

outra coisa que vai melhorar, e muito, é não fazer essas duas consultas. Você faz um select para saber o total de registros e outro pra listar, ou seja, consulmo em dobro.

 

você pode fazer assim:

<%
 connstring = "dsn=banco;uid=usuario;pwd=senha"

 Set conn = Server.CreateObject("ADODB.Connection")
Conn.CursorLocation = 3
 Conn.Open connString
 sql = "SELECT * FROM hoteis WHERE dados='dadosimaginários' ORDER BY diaria desc"
 Set rstTemp = Server.CreateObject("ADODB.RecordSet")
 rstTemp.Open sql, connstring, 3, 1
response.write "total de registro: " & rsTemp.RecordCount
 Do while not rstTemp.Eof
 Response.Write(rstTemp("Hotel") & " - " & rstTemp("Diaria"))
 rstTemp.MoveNext
 Loop

'continua e fecha tudo que ta aberto!
%>

Compartilhar este post


Link para o post
Compartilhar em outros sites

para usar o RecordCount seu cursor tem k estar com

recordset.CursorType = 3 (AdOpenDynamic)

como nosso amigo jonathandj disse

dependendo da situacaun melhor usar um contatdor normal ou a clausula count do SQL, pois se o seu bd for muito grande o recordcount do objeto recordset para apresentar queda de desempenho

 

exemplo:

 

<%
DIM mySQL, objRS
mySQL = "SELECT * FROM myTable" 
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open mySQL, objConn

' Count how many records exist
DIM iRecordCount
iRecordCount = 0
DO WHILE NOT objRS.EOF
iRecordCount = iRecordCount + 1
objRS.MoveNext
Loop

' Display result
Response.Write "(" & iRecordCount & ")"

objRS.Close
Set objRS = Nothing 
objConn.Close
Set objConn = Nothing
%> 

SQL COUNT

 

<!--#INCLUDE VIRTUAL="/includes/connection.asp" -->

<%
DIM mySQL, objRS
mySQL = "SELECT Count(*) AS intTotal FROM myTable" 
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open recSQL, objConn

' Display result
Response.Write objRS("intTotal")

objRS.Close
Set objRS = Nothing 
objConn.Close
Set objConn = Nothing
%>

Compartilhar este post


Link para o post
Compartilhar em outros sites

possivelmente seu problema seja minimizado ou até mesmo resolvido criando indices no banco de dados. Te digo que, dependendo do banco, não é necessário soluções alternativas no código. Trabalho com tabelas que tem milhares e algumas que tem milhões de registros e as consultas não levam mais que 2 segundos para serem executadas, mas pra isso as tabelas tem que estar bem montadas e bons indices criados.

 

outra coisa que vai melhorar, e muito, é não fazer essas duas consultas. Você faz um select para saber o total de registros e outro pra listar, ou seja, consulmo em dobro.

 

você pode fazer assim:

<%
 connstring = "dsn=banco;uid=usuario;pwd=senha"

 Set conn = Server.CreateObject("ADODB.Connection")
Conn.CursorLocation = 3
 Conn.Open connString
 sql = "SELECT * FROM hoteis WHERE dados='dadosimaginários' ORDER BY diaria desc"
 Set rstTemp = Server.CreateObject("ADODB.RecordSet")
 rstTemp.Open sql, connstring, 3, 1
response.write "total de registro: " & rsTemp.RecordCount
 Do while not rstTemp.Eof
 Response.Write(rstTemp("Hotel") & " - " & rstTemp("Diaria"))
 rstTemp.MoveNext
 Loop

'continua e fecha tudo que ta aberto!
%>

 

Bem, se eu usar a forma como você falou sim vai dobrar o processo, pois achar uma contagem usando este metodo vai fazer o banco de dados varrer todos registros usando tudo que tem pela frente pra fazer a contagem e isso sim iria prejudicar no desempenho.

 

O que tentei explicar é que uma contagem simples com comando direto seria mais viável neste caso (usando o Coun() ao invés de dar um super loop dentro do bando de dados e somar todos registros), já já concluo a real necessidade.

 

 

 

para usar o RecordCount seu cursor tem k estar com

recordset.CursorType = 3 (AdOpenDynamic)

como nosso amigo jonathandj disse

dependendo da situacaun melhor usar um contatdor normal ou a clausula count do SQL, pois se o seu bd for muito grande o recordcount do objeto recordset para apresentar queda de desempenho

 

exemplo:

 

<%
DIM mySQL, objRS
mySQL = "SELECT * FROM myTable" 
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open mySQL, objConn

' Count how many records exist
DIM iRecordCount
iRecordCount = 0
DO WHILE NOT objRS.EOF
iRecordCount = iRecordCount + 1
objRS.MoveNext
Loop

' Display result
Response.Write "(" & iRecordCount & ")"

objRS.Close
Set objRS = Nothing 
objConn.Close
Set objConn = Nothing
%> 

SQL COUNT

 

<!--#INCLUDE VIRTUAL="/includes/connection.asp" -->

<%
DIM mySQL, objRS
mySQL = "SELECT Count(*) AS intTotal FROM myTable" 
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open recSQL, objConn

' Display result
Response.Write objRS("intTotal")

objRS.Close
Set objRS = Nothing 
objConn.Close
Set objConn = Nothing
%>

 

Bem, no seu caso não entendi muito bem (a parte de abrir a chave do CursorType eu já sei e mantenho ela aberta pois utilizo outras opções que é necessaria seu uso).

O que não entendi é o seguinte, ou passei informação de menos ou vcs não entenderam a idéia. Então vou por partes:

 

O banco de dados é alterado diversas vezes, com registros automáticos sendo excluídos e sendo registrados no BD por muitos usuários ao mesmo tempo, então a idéia é a seguinte, eu tenho uma data que o BD vai expirar, por exemplo: 01/10/2009 e quando esta data já passou, as páginas todas do site contém um include que verifica o banco de dados e exclui automático isso sem que o usuário veja o que aconteceu, assim toda busca que ele fizer não vai encontrar as que ja passaram e o banco de dados não infla tanto deixando registros inúteis nele.

 

Acontece que são milhares de dados excluídos que expiram o tempo todo e outros milhares de dados adicionados o tempo todo, então, sempre que um usuário entra a rotina que limpa o banco de dados é executada e varre o banco de dados totalmente pra limpar os registros pra apagar, Então veio a idéia de buscar uma forma de não rpecisar abrir todo o banco de dados nesta busca e encontrei a funcionalidade perfeita em Maxrecords, pois assim ele mostra encontra somente a quantidade ideal que eu busco sem precisar procurar no banco de dados todo (nos que serão apagados e nos que não serão) até encontrar os dados que eu desejo. Porém, eu não tenho como definir um valor específico em maxrecods (como 10 por exemplo), pois como muita gente adiciona o tempo todo dados, pode acontecer de mais de 1000 registros estarem disponíveis pra rotina apagar ou apenas 1 deles estar pronto a ser excluído. Então surgiu a idéia de contar usando o comando "count(Id)" (onde Id é a chave primária dos registros), fazendo assim a rotina setar no maxrecords exataemnte o valor que seria visto na rotina que apagaria os registros.

 

Bem, agora acho que fui um pouco mais claro =)

outra dúvida que surgiu agora: "SELECT Count(*) AS intTotal FROM myTable"

Qual a finalidade do "AS intTotal"? intTotal seria uma celula da tabela? E qual a finalidade do comando "AS"?

 

Bem, obrigado aí pelas respostas até agora, estão me dando uma visão bem maior do que fazer e do que pode ser feito =)

 

Aliás, jonathandj

Dá uma idéia de como criar um indíce bom pro BD =)

Sou meio autodidata e daí me complico quando a coisa fica meio preta =\

Se souber onde posso encontrar mais informações sobre o assunto agradeço =)

Compartilhar este post


Link para o post
Compartilhar em outros sites

você viu que o total eu peguei pela propriedade do objeto?

 

o indice vai depender das colunas que são usadas na consulta. você precisa fazer o indice com na mesma ordem das colunas em que a maioria das consultas são executadas.

 

dê uma olhada nesse link http://msdn.microsoft.com/pt-br/library/ms188783.aspx

 

até agora você não disse qual o banco de dados que está usando

Compartilhar este post


Link para o post
Compartilhar em outros sites

"SELECT Count(*) AS intTotal FROM myTable"

 

intTotal - é o nome dá variavel k você esta atribuindo, poderia ser totalxan

 

E qual a finalidade do comando "AS"?

 

a cláusula AS permite que criar um aliás para identificar o resultado de saida da consulta

Compartilhar este post


Link para o post
Compartilhar em outros sites

jonathandj

 

Sobre a forma como pegou o total usando a propriedade foi boa, uso em diversos casos, porém, neste exato não serviria já que a idéia é exatamente limitar o número de linhas abertas no banco de dados e acredito que se não limitar no maxrecords isso acababaria fazendo com que todas as linhas existentes sejam abertas mesmo as que não estejam na lista de consulta para só então o sistema identificar quais pertencem aquela consulta ou não. Vou tentar rodar em um PC bem lento aqui um scrip usando:

 

var = rsTemp.RecordCount
rstTemp.MaxRecords = var

E daí veremos se vai funcionar =)

Ainda bem q não reciclei meus pcs antigos, ruim vai ser instalar um server em cima deles =P

 

Estou usando Acess (não sei pq desde q comecei a programar em asp sempre me basiei nele, desde 2000 =\

Acho que meio entendi a idéia de um índice, mas neste caso específico não tenho como fazer um pois os registros encontrados são excluídos ao invés de serem mostrados em uma consulta, mas usarei sim em outros casos, achei muito interessante =)

 

 

 

xanburzum

 

Ok, agora entendi =)

Já que você entende bem este tipo de condições, estava a um tempo atrás de algo que pegase 3 campos de uma tabela sendo um deles único e não tava conseguindo via "Select" normal, tive que fazer uma rotina completa pra poder filtrar o que procurava, veja se tem como fazer algo assim, mas que funcione:

 

"SELECT Distinct(Numero_Serie),Id,Nome,Endereço FROM myTable"

A idéia seria pegar os campos id, nome e endereço somente do que tivessem o Numero_Serie diferentes, mas quando chamo essa verificação no BD dava um problema(Não lembro se ele não distinguia por Numero_Serie os diferentes e dava todos ou se dava outro erro). Se souber de algo que funcione usando distinct, mas que dê pra selecionar outra celulas de uma mesma linha agrdeço =)

 

 

 

 

 

Obrigado pela força aí pessoal, tão me ajudando muito =)

Compartilhar este post


Link para o post
Compartilhar em outros sites

você pode pegar os campos id, nome e endereço .

 

A cláusula SQL DISTINCT é utilizada juntamente com a palavra chave SELECT para retornar um conjunto de dados com entradas exclusivas para a coluna de certos dados da tabela.

 

usando tabela de banco de clientes para ilustrar o uso do SQL DISTINCT.

 

Por exemplo, se quisermos selecionar todos os sobrenomes distintos da nossa tabela de clientes, vamos utilizar a seguinte instrução SQL DISTINCT:

 

SELECT DISTINCT LastName
FROM Customers 

 

ela serve para naun repetir o registro

 

para o Numero_Serie diferentes,você deve compará-los

Compartilhar este post


Link para o post
Compartilhar em outros sites

você pode pegar os campos id, nome e endereço .

 

A cláusula SQL DISTINCT é utilizada juntamente com a palavra chave SELECT para retornar um conjunto de dados com entradas exclusivas para a coluna de certos dados da tabela.

 

usando tabela de banco de clientes para ilustrar o uso do SQL DISTINCT.

 

Por exemplo, se quisermos selecionar todos os sobrenomes distintos da nossa tabela de clientes, vamos utilizar a seguinte instrução SQL DISTINCT:

 

SELECT DISTINCT LastName
FROM Customers 

 

ela serve para naun repetir o registro

 

para o Numero_Serie diferentes,você deve compará-los

 

Certo, mas a idéia é poder chamar outros campos sem precisar reabrir a sql, como por exemplo:

 

Set BlaBla = Conexao.Execute("SELECT DISTINCT LastName FROM Customers")
  If Not BlaBla.EOF Then
    Do While Not BlaBla.EOF

      Response.Write BlaBla("LastName") 'Este daqui funciona mas o de baixo não irá funcionar pq o distinct não deixa acessar outra opção
      Response.Write BlaBla("Cargo") 'Este daqui não aceita ser usado

    BlaBla.MoveNext
  End If
  BlaBla.CLose
Set BlaBla = Nothing

 

Como o exemplo acima não é possível abrir, por isso pedi se tem como chamar "Distinct(alguma_coisa),outra_coisa,re_outra_coisa"

ou qualquer forma mais prática de chamar as outras opções sem ter q usar assim:

 

 

Set BlaBla = Conexao.Execute("SELECT DISTINCT LastName FROM Customers")
  If Not BlaBla.EOF Then
    Do While Not BlaBla.EOF

      Set Outro_BlaBla = Conexao.Execute("SELECT * FROM Customers WHERE LastName='"& BlaBla("LastName") &"'")
        If Not Outro_BlaBla.EOF Then

          Response.Write Outro_BlaBla("LastName")
          Response.Write Outro_BlaBla("Cargo")

        End If
        Outro_BlaBla.Close
      Set Outro_BlaBla = Nothing


    BlaBla.MoveNext
  End If
  BlaBla.CLose
Set BlaBla = Nothing

A idéia é usar a mesma chamada SQL pra poder acessar o LastName único, mas poder chamar os outros campos da tabela sem precisar abrir outra chamada =)

Acho que é meio impossível fazer como estou querendo, mas vai q tem uma saída =P

 

 

 

 

Valeusão pela ajuda até agora =)

Devo estar enchendo o saco mais que o normal =P

Compartilhar este post


Link para o post
Compartilhar em outros sites

qual seu banco....

 

você consegue fazer isso usando SQL Server

 

e lembre-se ,não é permitido utilizar DISTINCT quando se tem um campo do tipo TEXT no seu select

Compartilhar este post


Link para o post
Compartilhar em outros sites

qual seu banco....

 

você consegue fazer isso usando SQL Server

 

e lembre-se ,não é permitido utilizar DISTINCT quando se tem um campo do tipo TEXT no seu select

 

Nunca testei com SQL Server =\

E sim, essa de campo numérico eu já sabia... eu uso acess em todas aplicações, pois não aprendi como usar outros bancos de dados =\

Compartilhar este post


Link para o post
Compartilhar em outros sites

Em vez de DISTINCT pode ser utilizada a palavra ALL para especificar o comportamento padrão de manter todas as linhas)

Como é óbvio, duas linhas são consideradas distintas quando têm pelo menos uma coluna diferente. Os valores nulos são considerados iguais nesta comparação.

 

Como alternativa, uma expressão arbitrária pode determinar quais linhas devem ser consideradas distintas:

 

 

SELECT DISTINCT ON (expressão [, expressão ...]) lista_de_seleção ...

 

Neste caso, expressão é uma expressão de valor arbitrária avaliada para todas as linhas. Um conjunto de linhas para as quais todas as expressões são iguais são consideradas duplicadas, e somente a primeira linha do conjunto é mantida na saída. Deve ser observado que a “primeira linha” de um conjunto é imprevisível, a não ser que a consulta seja ordenada por um número suficiente de colunas para garantir a ordem única das linhas que chegam no filtro DISTINCT (o processamento de DISTINCT ON ocorre após a ordenação do ORDER BY).

 

A cláusula DISTINCT ON não faz parte do padrão SQL, sendo algumas vezes considerada um estilo ruim devido à natureza potencialmente indeterminada de seus resultados.

ou

 

Select Count(distinct CAMPO1) AS Total

From TABELA

Group By CAMPO2

Having CAMPO2 = 3

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

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