Ir para conteúdo

POWERED BY:

Arquivado

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

Gabriel Heming

paginação dinâmica

Recommended Posts

Olá a todos,

 

Acredito que eu deveria utilizar outro título, entretanto, o problema apresentado aqui, é para a solução do título.

 

É interessante eu explicar todo o problema, ou os acontecimentos, para não deixar "pontas soltas"

 

Eu estava desenvolvendo uma solução para o sistema que da minha empresa. O sistema é desenvolvido em PHP e utiliza-se do SGBD MsSQL 2008 R2. Basicamente é um portal, simples. Entretanto, o meu problema é com uma questão de performance.

 

Eu utilizo a classe LimitIterator da biblioteca SPL do php para a paginação. Nunca tive problemas em questões de performance. Até esse momento.

 

A base de dados tratada, possui atualmente mais de 2700 registros. A consulta é rápida, não vou negar, quanto a isso, não há problema algum.

 

Entretanto, como a LimitIterator utiliza-se de todos os objetos para, assim então, definir o range de seleção (página 2 -> objetos de 10 até 20, por exemplo), o processo demora tempo de mais, coisa entre 4-6 segundos. O que para a web atual, é um tempo demasiado extenso.

 

Como o mssql, diferente de outros SGBDs, não implementa o método skip, eu estava utilizando uma view com a função ROW_NUMBER(), o que me atendia perfeitamente.

 

Segue o código:

 

SELECT 
   noticia.rownumber,
   noticia.id,  
   noticia.titulo, 
   noticia.resumo, 
   noticia.descricao, 
   noticia.datapublicacao
FROM
   (
       SELECT
           ROW_NUMBER() OVER (ORDER BY datapublicacao DESC) AS rownumber,
           *
       FROM 
    noticia
   ) AS noticia'

 

Eu omiti alguns campos, o que não vai afetar em nada para a solução do problema.

 

Essa view resolve parcialmente o problema. Entretanto, uma vez criada essa view, não há nenhuma possibilidade de se obter uma ordenação diferente da definida. O padrão, é pela ordem decrescente da data de publicação. Mas, caso eu necessite de alguma ordem diferente da definida, não funcionará, pois o ROW_NUMBER() gera a numeração conforme o parâmetro de ordenação do OVER.

 

Conversando com alguns desenvolvedores, chegamos ao consenso de criar uma função, passando então a o nome da coluna e o tipo de ordenação (ASC|DESC) por parâmetro. No desenvolvimento da function, descobrimos que, para utilizar os parâmetros como string/varchar, o SQL deve ser executado através da função EXECUTE(). Através de um select normal, não funciona utilizar variáveis para definir a coluna e o parâmetro de ordenação, somente através do execute.

Segue o código funcional:

 

DECLARE 
   @column varchar(50),
   @order varchar(4)
SET 
   @column = 'datapublicacao'
SET
   @order = 'DESC'
execute (
   'SELECT 
       noticia.rownumber,
       noticia.id,  
       noticia.titulo, 
       noticia.resumo, 
       noticia.descricao, 
       noticia.datapublicacao
   FROM
       (
       SELECT
           ROW_NUMBER() OVER (ORDER BY '+ @column + ' ' + @order + ') AS rownumber,
           *
       FROM 
           noticia
       ) AS noticia'
   )

 

 

O código acima resolve totalmente o meu problema. Entretanto, quando fui criar a function.

 

CREATE FUNCTION noticiapaginacao(@column varchar(50) , @order varchar(4)) 
RETURNS @noticiapaginacao TABLE (
   rownumber INT,
   id INT, 
   titulo VARCHAR(255), 
   resumo TEXT, 
   descricao TEXT, 
   datapublicacao DATETIME
) AS
BEGIN
   execute (
   '
   INSERT @noticiapaginacao 
   SELECT 
       noticia.rownumber,
       noticia.id,  
       noticia.titulo, 
       noticia.resumo, 
       noticia.descricao, 
       noticia.datapublicacao
   FROM
       (
           SELECT
               ROW_NUMBER() OVER (ORDER BY '+ @column + ' ' + @order + ') AS rownumber,
               *
           FROM 
               noticia
           ) AS noticia'
      )        
   RETURN
END

 

 

Quando tento criar essa função, o seguinte erro é lançado.

Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.

 

Pela simples tradução, pude perceber que, a função execute, não pode ser utilizada dentro de uma function. Minha intenção com isso é, dentro das possibilidades de ambas as ferramentas (MsSQL/PHP) encontrar uma solução para esse problema. Não me importo em fazer de uma maneira diferente, mas essa foi a mais lógica encontrada, já que o PHP em si, está tendo dificuldades em processar tamanha quantidade de dados.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Isto não me parece ser um problema do mssql.

 

Pq não faz sua própria paginação invés de usar o LimitIterator?

 

Não entendi quando você fala sobre a função SKIP, o que você deseja?

Se estiver se referindo ao OFFSET, o MSSQL tem uma implementação.

Veja aqui: http://msdn.microsoft.com/en-us/library/gg699618.aspx

Compartilhar este post


Link para o post
Compartilhar em outros sites

Exatamente, é o offset. EM algum lugar, acho que foi no W3Schools que li que o nome do método é skip. Entretanto, eu pesquisei sobre isso, não encontrei nada. Principalmente no stack overflow, a resposta era sempre a mesma, utilize row_number() para obter determinado range de resultados.

 

Eu estava querendo fazer sem a LimitIterator, entretanto, em todo o lugar que eu pesquisa, foi sempre a mesma resposta: "MsSQL não dá suporte"...

 

Assim que estiver no trabalho, irei testar.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pode-se usar CTE ao inves de views diretamente. A performance é mto melhor. Exemplo prático e já utilizo em alguns clientes:

http://forum.imasters.com.br/topic/323465-clausula-semelhante-ao-limit-do-mysql/

 

Abçs

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Prog, estou pensando seriamente em mandar atualizar isso, pena que não depende só, e somente só, de mim.

 

Então @A.JR, já utilizava CTE, o problema ficava em utilizar ORDER BY diferentes. Não se tornava "trivial" a alteração. Uma vez que deveria ser utilizado em mais de um lugar. Mais por facilidade mesmo.

 

Como segunda parte da dúvida, fica também em queries dinâmicas dentro de uma function sql. Mas isso é só uma dúvida apresentada anteriormente.

 

Estarei fazendo uma modificações, e caso eu chegar a uma solução definitiva, dentro do escopo que possuo, postarei aqui.

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.