ventajas una sirve relacional que para modelo estructura ejemplos ejemplo desventajas datos caracteristicas sql database django django-models

sql - una - modelo relacional



Representar ordenando en una base de datos relacional (10)

Como en general me he topado con esto con Django, creo que esta solución es la más viable. Parece que no hay una "forma correcta" de hacerlo en una base de datos relacional.

Tengo una colección de objetos en una base de datos. Imágenes en una galería de fotos, productos en un catálogo, capítulos en un libro, etc. Cada objeto se representa como una fila. Quiero poder ordenar estas imágenes de forma arbitraria, almacenando ese orden en la base de datos para que cuando muestre los objetos, estén en el orden correcto.

Por ejemplo, digamos que estoy escribiendo un libro, y cada capítulo es un objeto. Escribo mi libro y coloco los capítulos en el siguiente orden:

Introducción, accesibilidad, forma vs. función, errores, consistencia, conclusión, índice

Va al editor y vuelve con el siguiente orden sugerido:

Introducción, forma, función, accesibilidad, consistencia, errores, conclusión, índice

¿Cómo puedo almacenar este orden en la base de datos de una manera robusta y eficiente?

He tenido las siguientes ideas, pero no estoy entusiasmado con ninguna de ellas:

  1. Formación. Cada fila tiene una ID de pedido, cuando se cambia la orden (a través de una eliminación seguida de una inserción), se actualizan las ID de la orden. Esto hace que la recuperación sea fácil, ya que solo es ORDER BY , pero parece fácil de romper.

    // REMOVAL
    UPDATE ... SET orderingID=NULL WHERE orderingID=removedID
    UPDATE ... SET orderingID=orderingID-1 WHERE orderingID > removedID
    // INSERTION
    UPDATE ... SET orderingID=orderingID+1 WHERE orderingID > insertionID
    UPDATE ... SET orderID=insertionID WHERE ID=addedID

  2. Lista enlazada. Cada fila tiene una columna para el ID de la siguiente fila en el orden. El recorrido parece costoso aquí, aunque es posible que de alguna forma use ORDER BY que no estoy pensando.

  3. Matriz espaciada Establezca orderingID (como se usa en # 1) para que sea grande, entonces el primer objeto es 100, el segundo es 200, etc. Luego, cuando ocurre una inserción, simplemente la coloca en (objectBefore + objectAfter)/2 . Por supuesto, esto debería reequilibrarse de vez en cuando, para que no tenga cosas muy juntas (incluso con flotadores, eventualmente se encontraría con errores de redondeo).

Ninguno de estos parece particularmente elegante para mí. ¿Alguien tiene una mejor manera de hacerlo?


Haría un número consecutivo, con un disparador sobre la mesa que "da lugar" a una prioridad si ya existe.


Hice esto en mi último proyecto, pero fue para una tabla que solo ocasionalmente necesitaba pedirse específicamente, y no se accedía con demasiada frecuencia. Creo que la matriz espaciada sería la mejor opción, porque el reordenamiento sería más barato en el caso promedio, con solo un cambio en un valor y una consulta en dos).

Además, me imagino que ORDER BY sería bastante optimizado por los proveedores de bases de datos, por lo que aprovechar esa función sería ventajoso para el rendimiento en comparación con la implementación de la lista vinculada.


La mezcla de act_as_list en Rails maneja esto básicamente de la forma en que se delineó en # 1. Busca una columna INTEGER llamada posición (de la cual puede anular el nombre del curso) y la usa para hacer un ORDER BY. Cuando desee volver a pedir cosas, actualice las posiciones. Me ha servido muy bien cada vez que lo he usado.

Como nota al margen, puede eliminar la necesidad de volver a posicionar siempre en INSERTS / DELETES mediante el uso de numeración dispersa - algo así como básico en el día ... puede numerar sus posiciones 10, 20, 30, etc. y si necesita insertar algo entre 10 y 20, solo debe insertarlo en una posición de 15. Del mismo modo, al eliminar puede simplemente eliminar la fila y dejar el espacio. Solo necesita volver a numerar cuando realmente cambia el pedido o si trata de hacer un inserto y no hay espacio adecuado para insertarlo.

Por supuesto, dependiendo de su situación particular (por ejemplo, si tiene las otras filas ya cargadas en la memoria o no) puede o no tener sentido utilizar el enfoque de brecha.


Otra alternativa sería (si su RDBMS lo admite) usar columnas de tipo array. Si bien esto rompe las reglas de normalización, puede ser útil en situaciones como esta. Una base de datos que sé que tiene matrices es PostgreSQL.


Si los objetos no están fuertemente codificados por otras tablas, y las listas son cortas, borrar todo en el dominio y simplemente reinsertar la lista correcta es lo más fácil. Pero eso no es práctico si las listas son grandes y tiene muchas limitaciones para ralentizar la eliminación. Creo que tu primer método es realmente el más limpio. Si lo ejecuta en una transacción, puede estar seguro de que no ocurre nada extraño mientras está en el medio de la actualización para arruinar el pedido.


Solo un pensamiento considerando la opción n. ° 1 vs n. ° 3 : ¿la opción de matriz espaciada (n. ° 3) no pospone el problema de la matriz normal (n. ° 1)? Sea cual sea el algoritmo que elija, o está roto, y tendrá problemas con el # 3 más tarde, o funciona, y luego el # 1 debería funcionar igual de bien.


Tuve el mismo problema y probablemente haya pasado al menos una semana sobre el modelado de datos adecuado, pero creo que finalmente lo tengo. Utilizando el tipo de datos de matriz en PostgreSQL, puede almacenar la clave principal de cada elemento ordenado y actualizar dicha matriz en consecuencia utilizando inserciones o eliminaciones cuando cambie su orden. Hacer referencia a una sola fila te permitirá mapear todos tus objetos según el orden en la columna de la matriz.

Todavía es un poco entrecortado de una solución, pero es probable que funcione mejor que la opción n.º 1, ya que la opción 1 requiere la actualización del número de orden de todas las otras filas al hacer el pedido de cambios.


Use un número de coma flotante para representar la posición de cada artículo:

Artículo 1 -> 0.0

Artículo 2 -> 1.0

Artículo 3 -> 2.0

Artículo 4 -> 3.0

Puede colocar cualquier elemento entre otros dos elementos por simple bisección:

Artículo 1 -> 0.0

Artículo 4 -> 0.5

Artículo 2 -> 1.0

Artículo 3 -> 2.0

(Artículo movido 4 entre los artículos 1 y 2).

El proceso de bisección puede continuar casi indefinidamente debido a la forma en que los números de punto flotante están codificados en un sistema informático.

Artículo 4 -> 0.5

Artículo 1 -> 0.75

Artículo 2 -> 1.0

Artículo 3 -> 2.0

(Mueva el ítem 1 a la posición justo después del Ítem 4)


Yo tuve este problema también. Estuve bajo una gran presión de tiempo (no somos todos) y elegí la opción n. ° 1, y solo cambié las filas que cambiaron.

Si intercambia el ítem 1 con el ítem 10, solo haga dos actualizaciones para actualizar los números de pedido del ítem 1 y el ítem 10. Sé que es algorítmicamente simple, y es el O (n) peor caso, pero el peor caso es cuando tiene una permutación total de la lista. ¿Con qué frecuencia va a pasar eso? Eso es para que respondas.