Estoy construyendo una base de datos con Postgres donde habrá muchas agrupaciones de cosas por monthy year, pero nunca por date.
- Podría crear enteros
monthyyearcolumnas y usarlos. - O podría tener una
month_yearcolumna y siempre establecer elday1.
El primero parece un poco más simple y claro si alguien está mirando los datos, pero el segundo es bueno porque usa un tipo apropiado.
postgresql
database-design
datetime
David N. Welton
fuente
fuente

monthque contenga dos enteros. Pero creo que si nunca necesitas el día del mes, usar dos enteros probablemente sea más fácilRespuestas:
Personalmente, si es una fecha, o puede ser una fecha, sugiero que siempre la almacene como una. Es más fácil trabajar con él como regla general.
Puede tener una fecha que admitirá el día si alguna vez la necesita, o una
smallintpara año y mes que nunca admitirá la precisión adicional.Data de muestra
Veamos un ejemplo ahora ... Creemos 1 millón de fechas para nuestra muestra. Esto es aproximadamente 5,000 filas por 200 años entre 1901 y 2100. Cada año debería tener algo para cada mes.
Pruebas
Sencillo
WHEREAhora podemos probar estas teorías de no usar la fecha. Ejecuté cada una de estas veces para calentar las cosas.
Ahora, intentemos el otro método con ellos separados
Para ser justos, no todos son 0.749 ... algunos son un poco más o menos, pero no importa. Todos son relativamente iguales. Simplemente no es necesario.
En un mes
Ahora, divirtámonos ... Digamos que desea encontrar todos los intervalos dentro de 1 mes de enero de 2014 (el mismo mes que utilizamos anteriormente).
Compare eso con el método combinado
Es a la vez más lento y más feo.
GROUP BY/ /ORDER BYMétodo combinado,
Y nuevamente con el método compuesto
Conclusión
En general, deje que las personas inteligentes hagan el trabajo duro. Datemath es difícil, mis clientes no me pagan lo suficiente. Solía hacer estas pruebas. Me costaba mucho concluir que podría obtener mejores resultados que
date. Dejé de intentarlo.ACTUALIZACIONES
@a_horse_with_no_name sugerido para mi prueba dentro de un mes
WHERE (year, month) between (2013, 12) and (2014,2). En mi opinión, si bien es una consulta más compleja, prefiero evitarla a menos que haya una ganancia. Por desgracia, aún fue más lento, aunque está cerca, lo que es más fácil de quitar de esta prueba. Simplemente no importa mucho.fuente
datees el camino a seguir en la mayoría de los casos.Como alternativa al método propuesto por Evan Carroll, que considero probablemente la mejor opción, he usado en algunas ocasiones (y no especialmente cuando uso PostgreSQL) solo una
year_monthcolumna, de tipoINTEGER(4 bytes), calculada comoEs decir, codifica el mes en los dos dígitos decimales más a la derecha (dígito 0 y dígito 1) del número entero, y el año en los dígitos 2 a 5 (o más, si es necesario).
Esta es, hasta cierto punto, la alternativa de un hombre pobre para construir su propio
year_monthtipo y operadores. Tiene algunas ventajas, principalmente "claridad de intención", y algunos ahorros de espacio (no en PostgreSQL, creo), y también algunos inconvenientes, al tener dos columnas separadas.Puede garantizar que los valores son válidos simplemente agregando un
Puede tener una
WHEREcláusula que se vea así:y funciona de manera eficiente (si la
year_monthcolumna está indexada correctamente, por supuesto).Puede agrupar de
year_monthla misma manera que podría hacerlo con una fecha y con la misma eficiencia (al menos).Si necesita separarse
yearymonth, el cálculo es sencillo:Lo que es inconveniente : si desea agregar 15 meses a uno
year_month, debe calcular (si no he cometido un error o supervisión):Si no tiene cuidado, esto puede ser propenso a errores.
Si desea obtener la cantidad de meses entre dos años-meses, debe hacer algunos cálculos similares. Eso es (con muchas simplificaciones) lo que realmente sucede debajo del capó con la aritmética de fechas, que afortunadamente se nos oculta a través de funciones y operadores ya definidos.
Si necesita muchas de estas operaciones, el uso
year_monthno es demasiado práctico. Si no lo hace, es una forma muy clara de aclarar su intención.Como alternativa, podría definir un
year_monthtipo, y definir un operadoryear_month+interval, y también otroyear_month-year_month... y ocultar los cálculos. En realidad nunca he hecho un uso tan intenso como para sentir la necesidad en la práctica. Adate- endaterealidad te está ocultando algo similar.fuente
Como alternativa al método de joanolo =) (lo siento, estaba ocupado pero quería escribir esto)
ALEGRÍA
Vamos a hacer lo mismo, pero con bits. Uno
int4en PostgreSQL es un entero con signo, que va desde -2147483648 hasta +2147483647Aquí hay una descripción general de nuestra estructura.
Almacenamiento mes.
pow(2,4)es de 4 bits .Aquí está nuestro mapa de bits de dónde se almacenan los meses.
Meses, 1 de enero - 12 de diciembre
Años. Los 28 bits restantes nos permiten almacenar nuestra información anual
En este punto, necesitamos decidir cómo queremos hacer esto. Para nuestros propósitos, podríamos usar un desplazamiento estático, si solo necesitamos cubrir 5,000 AD, podríamos volver a lo
268,430,455 BCque cubre casi todo Mesozoic y todo lo útil en el futuro.Y, ahora tenemos los rudimentos de nuestro tipo, que expiran en 2.700 años.
Así que manos a la obra para hacer algunas funciones.
Una prueba rápida muestra que esto funciona ...
Ahora tenemos funciones que podemos usar en nuestros tipos binarios.
Podríamos haber cortado un poco más de la parte firmada, almacenado el año como positivo, y luego haberlo ordenado naturalmente como un int firmado. Si la velocidad fuera una prioridad más alta que el espacio de almacenamiento, esa habría sido la ruta que seguimos. Pero por ahora, tenemos una fecha que funciona con el Mesozoico.
Puedo actualizar más tarde con eso, solo por diversión.
fuente