Genial, por ejemplo en Laravel la implementacion de paginacion por cursores es la mejor, en la misma documentacion se habla de como el uso de limits es la menos eficiente en grandes conjuntos de datos.
Otra cosa que no habéis mencionado es que para el paginado por offset hay que leer la tabla entera hasta llegar a la fila que se desea. Traer páginas se vuelve por ende cada vez más difícil, y de ahí que haya límites. Es una operación costosa, pero simple de ejecutar. En resumen: paginación por offset hasta que empiece a haber cuello de botella. De ahí a cursor
He utilizado para paginar el Rownum y el Row Over según el motor, siempre usando como limite principal la fecha de inserción, algo que vi recientemente es el uso de la fecha como un tipo entero haciendo que la consulta sea mas rápida
En su momento yo utlizaba los ID y el número total de registros para realizar los cálculos de paginación. Nunca tuve la oportunidad de comparar lo que hice con otra forma.
No lo he visto comentado, así que os hago una pregunta. Hablais de lo que pasa cuando en un offset se elimina/crea un registro, pero no mencionais cuando en un cursor se modifica un registro, pasaría lo mismo que en un offset se crea/elimina Pongo un ejemplo con el ejemplo que habéis puesto de twitch: Yo estoy buscando por viewers, que tengan menos de 32, pero si en ese momento uno de los que estaban por debajo antes de que lo encuentre pasa a tener más, tampoco lo voy a encontrar, en este caso tendría el mismo problema. Lo mismo pasa con la relevancia si al momento de buscar a cambiado Que opinais al respecto? Habría alguna forma de solucionarlo?
Pero la forma de representar en la UI no necesariamente esta determinada por como funciona en el back (O si?). Osea, el ejemplo del cursor que muestran lo único que determina es un punto de inicio o fin para traer registros del backend, y los registros que se traen no son todos sino los del grupo que el cursor representa; se supone que otros registros ya fueron mostrados, y el resultado final es que nuevos registros aparecen en la ui al final (manteniéndose los anteriores). Esa misma forma de mostrar los registros en la ui con una lista infinita podria lograrse usando offset, porque si el registro no viene (porque se borró) no importa porque ya es parte del listado que ya se esta mostrando en la UI, y si viene duplicado eso podria detectarse con un ID y eliminarse (el registro) desde la UI para evitar ser mostrado 2 veces. Si lo pensamos al revés, osea un listado tradicional (no scroll infinito), que funcionase con cursores podría tener el mismo problema que los que plantean en el páginado por offset (registros que se omiten por ser borrados o duplicados) por supuesto teniendo en cuenta el criterio que usemos para armar el cursor (en el ejemplo del video son cantidad de visualizacion y las mismas pueden cambiar con el tiempo).
Si miran el json del request van a ver que hay un parámetro limit = 30. En el back tranquilamente esa API que se llama podría ser una llamada a otra API existente que ya funciona con paginado usando offset (ej, porque se precisaban tener 2 apis que funcionen diferente). Entonces esta nueva API (que recibe como entrada el pagesize=30, la "S=32.11420945616304", la "D" y la "T"), podría llamar a la otra API más vieja pasando como parámetros: ?s={32.11420945616304}&page=0&PageSize=30. Adentro la implementacion simplemente tendria un select con el criteria, un limit de 30 y offset 0; pero aunque puede ser mas performante (por usar siempre offset 0), potencialmente sigue teniendo los "problemas" que el video plantea respecto a registros nuevos y eliminados.
No entendí o no le encontré el sentido, si la paginación se hace estática se pierde lo que pase entre ese tiempo y el refresh, pero si la paginación es dinámica el riesgo es bajo, no se si cercano a improbable si es que no se trata de cientos de miles o millones de registros. ¿No?
Creo que en este caso se podría aplicar lo que comentaron del timestamp, se podría usar una expresión del tipo: WHERE relevance > X OR (relevance = X AND id > Y)
en ese caso el orden en que se muestran los productos no tiene importancia, ahora si deseas darle algun orden agregarias algo mas al order by y agregarias un filtro mas, por lo tanto tu cursos ya no seria solo relevancia como en el caso de twitch q tenia 3 parametros
Conviertan el puntero a base 64 y pasenlo por url cuál problema hay xd Y bueno, pueden usar ids autoincrementales y uids al mismo tiempo, no hay problema
Con esto se me ocurrió esto para usarlo con parametos: set @page = 3; Set @Skip = (10 *(@page -1)); select * from actor where first_name like "%" and actor_id > @Skip order by actor_id asc limit 10;
diría que no es una implementación correcta de cursores, la forma en como calculas @skip es con valores absolutos y asumiendo que actor_id es auto increment y que por ejemplo si haces query a la pagina 2 y no hay un actor con id 9 el actor 11 apareceria dos veces(pagina 1 y 2) lo ideal es tomar el ultimo id para generar la siguiente consulta actor_id > @last_actor_from_page_1
Hoy aprendí algo nuevo.. Muchas Gracias
Genial, por ejemplo en Laravel la implementacion de paginacion por cursores es la mejor, en la misma documentacion se habla de como el uso de limits es la menos eficiente en grandes conjuntos de datos.
Lo ineficiente es el uso de offset, no de limit. El limit sigue siendo necesario para implementar paginación por cursores.
Interesante, es una buena discusion para distintos casos de usos en donde se priorize el Performance and User Experience.
Buenisimo! Muchas gracias por este aporte!!
Excelente explicación 👏
Muy bueno... Hasta la fecha no me había planteado que hubiera otro modo de paginar que con offset y limit. Muy instructivo e interesante!!
Muchas gracias por compartir!! Grandes
que calidad lo necesitaba
Él sistema de cursores cuando tienes que ordenar por más de 2 campos (cosa que no suele ser habitua)l hace que montar la query sea un infierno.
Otra cosa que no habéis mencionado es que para el paginado por offset hay que leer la tabla entera hasta llegar a la fila que se desea. Traer páginas se vuelve por ende cada vez más difícil, y de ahí que haya límites. Es una operación costosa, pero simple de ejecutar.
En resumen: paginación por offset hasta que empiece a haber cuello de botella. De ahí a cursor
Uhm no hay una forma de hacerlo X10 con offset
He utilizado para paginar el Rownum y el Row Over según el motor, siempre usando como limite principal la fecha de inserción, algo que vi recientemente es el uso de la fecha como un tipo entero haciendo que la consulta sea mas rápida
Puedes explicar de que se trata lo de fecha de tipo entero? tendrás algún pequeño ejemplo?
En su momento yo utlizaba los ID y el número total de registros para realizar los cálculos de paginación.
Nunca tuve la oportunidad de comparar lo que hice con otra forma.
En algún momento pensé en esto, pero hasta el día de hoy, no sé cómo se podría implementar en código
ya veo, gracias
No lo he visto comentado, así que os hago una pregunta.
Hablais de lo que pasa cuando en un offset se elimina/crea un registro, pero no mencionais cuando en un cursor se modifica un registro, pasaría lo mismo que en un offset se crea/elimina
Pongo un ejemplo con el ejemplo que habéis puesto de twitch:
Yo estoy buscando por viewers, que tengan menos de 32, pero si en ese momento uno de los que estaban por debajo antes de que lo encuentre pasa a tener más, tampoco lo voy a encontrar, en este caso tendría el mismo problema.
Lo mismo pasa con la relevancia si al momento de buscar a cambiado
Que opinais al respecto? Habría alguna forma de solucionarlo?
min 6:48, ¿Será una buena práctica usar los IDs autoincrementales cuando los hay, en lugar de crear una nueva columna para la relevancia?
si, lo aclaran en el 11:11
@@darpex_63Gracias!
Y qué tal el uso de key set?
Pero la forma de representar en la UI no necesariamente esta determinada por como funciona en el back (O si?). Osea, el ejemplo del cursor que muestran lo único que determina es un punto de inicio o fin para traer registros del backend, y los registros que se traen no son todos sino los del grupo que el cursor representa; se supone que otros registros ya fueron mostrados, y el resultado final es que nuevos registros aparecen en la ui al final (manteniéndose los anteriores). Esa misma forma de mostrar los registros en la ui con una lista infinita podria lograrse usando offset, porque si el registro no viene (porque se borró) no importa porque ya es parte del listado que ya se esta mostrando en la UI, y si viene duplicado eso podria detectarse con un ID y eliminarse (el registro) desde la UI para evitar ser mostrado 2 veces. Si lo pensamos al revés, osea un listado tradicional (no scroll infinito), que funcionase con cursores podría tener el mismo problema que los que plantean en el páginado por offset (registros que se omiten por ser borrados o duplicados) por supuesto teniendo en cuenta el criterio que usemos para armar el cursor (en el ejemplo del video son cantidad de visualizacion y las mismas pueden cambiar con el tiempo).
Si miran el json del request van a ver que hay un parámetro limit = 30. En el back tranquilamente esa API que se llama podría ser una llamada a otra API existente que ya funciona con paginado usando offset (ej, porque se precisaban tener 2 apis que funcionen diferente). Entonces esta nueva API (que recibe como entrada el pagesize=30, la "S=32.11420945616304", la "D" y la "T"), podría llamar a la otra API más vieja pasando como parámetros: ?s={32.11420945616304}&page=0&PageSize=30. Adentro la implementacion simplemente tendria un select con el criteria, un limit de 30 y offset 0; pero aunque puede ser mas performante (por usar siempre offset 0), potencialmente sigue teniendo los "problemas" que el video plantea respecto a registros nuevos y eliminados.
No entendí o no le encontré el sentido, si la paginación se hace estática se pierde lo que pase entre ese tiempo y el refresh, pero si la paginación es dinámica el riesgo es bajo, no se si cercano a improbable si es que no se trata de cientos de miles o millones de registros. ¿No?
con cursores quitas el problema de que el usuario vea inconsistencia en la lista de elementos cuando esta se actualiza
Con scroll infinito (cursor), cómo haces SEO si no hay un link visible para el usuario a la siguiente página?
Ojo. Paginar a nivel de base de datos con cursor no implica que a nivel de interfaz de usuario se tenga que implementar un scroll infinito
¿Qué pasa si hay más de un producto con la misma relevancia? Entiendo que ese campo no es único para cada producto
Creo que en este caso se podría aplicar lo que comentaron del timestamp, se podría usar una expresión del tipo: WHERE relevance > X OR (relevance = X AND id > Y)
en ese caso el orden en que se muestran los productos no tiene importancia, ahora si deseas darle algun orden agregarias algo mas al order by y agregarias un filtro mas, por lo tanto tu cursos ya no seria solo relevancia como en el caso de twitch q tenia 3 parametros
Cursor vs offset lo explican bien en la docu de prisma
En ws me ha pasado que he visto el mismo mensaje 2 veces, y si salgo de la conversación y vuelvo a entrar ya se arregla 😂
Relevancia es un autoincremental? O cual es su implementación!!
según entiendo, sí.
La sacamos en el select según el tipo de ordenamiento que queramos
Conviertan el puntero a base 64 y pasenlo por url cuál problema hay xd
Y bueno, pueden usar ids autoincrementales y uids al mismo tiempo, no hay problema
Para este tipo de cosas llamen a un experto en base de datos. Ahi si que van a aprenderr
¿Ellos no son expertos? :0
@@mitchelnunez753 en database??? Lo son???
@@mitchelnunez753 nop.
@@mitchelnunez753 en dB? Ufff se nota que nunca has hablado con un tipo full db
Con esto se me ocurrió esto para usarlo con parametos:
set @page = 3;
Set @Skip = (10 *(@page -1));
select * from actor where first_name like "%" and actor_id > @Skip order by actor_id asc limit 10;
diría que no es una implementación correcta de cursores, la forma en como calculas @skip es con valores absolutos y asumiendo que actor_id es auto increment y que por ejemplo si haces query a la pagina 2 y no hay un actor con id 9 el actor 11 apareceria dos veces(pagina 1 y 2) lo ideal es tomar el ultimo id para generar la siguiente consulta actor_id > @last_actor_from_page_1
@@IamTheLastDev Si tienes razón es que lo probé con registros que no saltan pero al eliminarse uno o varios se genera el problema.