2012-05-01 16 views
5

Esta es una pregunta completamente hipotética: digamos que tengo una base de datos donde necesito almacenar membresías para un usuario, que puede durar un tiempo específico (1 mes, 3 meses, 6 meses, 1 año, etc.).En una base de datos, ¿es mejor almacenar un período de tiempo como una fecha de inicio/finalización, o una fecha de inicio y un período de tiempo?

¿Es mejor tener una mesa Memberships que tiene campos (cada fecha se almacena como una marca de tiempo Unix):

user_id INT, start_date INT, end_date INT

o para almacenarla como:

user_id INT , start_date INT, length INT

De cualquier forma, puede buscar usuarios con miembros activos cadera (por ejemplo). Para la última situación, la aritmética debería realizarse cada vez que se ejecuta la consulta, mientras que la situación anterior solo requiere que la fecha de finalización se calcule una vez (en la inserción). Desde este punto de vista, parece que el diseño anterior es mejor, pero ¿hay algún inconveniente? ¿Hay algún problema común que se pueda evitar almacenando la longitud, que no se puede evitar almacenando la fecha?

Además, ¿son las marcas de tiempo unix el camino a seguir cuando se almacenan datos de fecha y hora, o se prefiere algo como DATETIME? Me he encontrado con problemas con ambos tipos de datos (conversiones excesivas) pero generalmente me fijo en los sellos de tiempo de Unix. Si se prefiere algo como DATETIME, ¿cómo cambia esto la respuesta a mi pregunta de diseño anterior?

+0

¿No sería la respuesta a esta pregunta depende del sistema? Ambas soluciones me parecen buenas, pero si ninguna de sus consultas se preocupa por la duración, entonces el primer caso es mejor. De lo contrario, podría ser de otra manera. Además, si tiene consultas pesadas que utilizan la longitud y las consultas pesadas que usan la fecha de finalización, es posible que desee almacenar ambos valores en su base de datos. –

Respuesta

2

Realmente depende del tipo de consultas que ejecutará en contra de su fecha. Si las consultas involucran búsqueda por hora de inicio/finalización o rango de fechas, entonces inicio/y fecha, entonces definitivamente vaya con la primera opción.

Si le interesan más las estadísticas (¿Cuál es el período de membresía promedio? ¿Cuántas personas son miembros durante más de un año?), Entonces elegiría la segunda opción.

En cuanto a la conversión excesiva, ¿en qué idioma está programando? Java/Ruby usa Joda Time bajo el capó y simplifica mucho la lógica relacionada con la fecha/hora.

+0

+1 Buena captura en estadística;) –

+0

Creo que una combinación de esta respuesta y la de Branko es la mejor, pero solo puedo aceptar una ... Te la daré porque tu representante es más bajo. –

+0

Buena llamada :-) lol –

0

Desde el punto de vista del diseño, considero que es un mejor diseño tener una fecha de inicio y la duración de la membresía.

La fecha de finalización es una derivación de la fecha de inicio de la membresía + duración. Así es como pienso en eso.

1

No estoy de acuerdo. Tendría una fecha de inicio y finalización: ahorre en la realización de cálculos todo el tiempo.

1

Las dos estrategias son funcionalmente equivalentes, elija su favorito.

2

Si depende de si desea índice la fecha de finalización, que a su vez depende de cómo desea consultar los datos.

Si lo hace, y si su DBMS no admite índices basados ​​en funciones o índices en columnas calculadas, entonces su único recurso es tener un end_date físico para que pueda indexarlo directamente.

Aparte de eso, no veo mucha diferencia.

Por cierto, utilice el tipo de fecha nativa que su DBMS proporciona, no int. Primero, obtendrá algún tipo de seguridad de tipo (por lo que obtendrá un error si intenta leer/escribir un int donde se espera la fecha), le impedirá incluir una integridad referencial que no coincide (aunque los FK en las fechas son raros) , puede manejar zonas horarias (dependiendo de DBMS), DBMS generalmente le proporcionará las funciones para extraer componentes de fecha, etc. ...

+0

+1, buena captura en el índice. –

0

Si el número de miembros puede cambiar con el tiempo yo sugeriría esta opción:

user_id INT, 
since_date DATE, 
active_membership BIT 

donde el estado active_membership es lo que se alterna con el tiempo, y la since_date es mantener un registro de cuando esto sucedió. Por otra parte, si usted tiene conjunto finito de longitudes de miembros autorizados y la necesidad de no perder de vista lo que la longitud de un determinado usuario ha escogido, esto puede ser extendido a:

user_id INT, 
since_date DATE, 
active_membership BIT, 
length_id INT 

donde length_id haría referencia a una tabla de búsqueda de disponible y permitido longitudes de membresía. Sin embargo, tenga en cuenta que en este caso since_date se vuelve ambiguo si es posible cambiar la duración de su membresía. En ese caso, tendría que extender esta aún más:

user_id INT, 
active_membership_since_date DATE, 
active_membership BIT, 
length_since_date DATE, 
length_id INT 

Con este enfoque, es fácil ver que la normalización se rompe cuando las dos fechas cambian de forma asíncrona. Para mantener esto normalizado, realmente necesitas 6NF. Si sus requisitos van en esta dirección, le sugiero que busque en Anchor modeling.

Cuestiones relacionadas