Se me ha pedido que cree algo que rastree el costo diario para cobrar en las cuentas, y estoy tratando de descubrir un esquema de tabla de base de datos que lo respalde.
Esto es lo que se
- La compañía tiene más de 2.5 millones de cuentas.
- De estos, actualmente trabajan un promedio de 200,000 por mes (que cambia con los niveles de personal, que actualmente son bajos)
- Tienen 13 tipos de costos diferentes que les gustaría rastrear, y han advertido que podrían agregar más en el futuro
- Quieren que los costos sean rastreados diariamente
- Los costos no se dividen en todo el inventario. Se dividen en el número de cuentas que se trabajan por mes (200,000), o los usuarios pueden ingresar identificadores de cuenta para aplicar un costo a un grupo de cuentas, o simplemente pueden especificar a qué cuentas aplicar el costo.
Mi primer pensamiento fue una base de datos normalizada:
ID de la cuenta Fecha CostTypeId Cantidad
Mi problema con esto es hacer los cálculos. Esta mesa se va a poner enorme rápidamente. Suponiendo que los 13 tipos de costos se apliquen a todas las cuentas trabajadas para el mes actual, es decir 200k * 13 * N days in month
, alrededor de 75-80 millones de registros por mes, o cerca de mil millones de registros por año.
Mi segundo pensamiento fue desnormalizarlo un poco
ID de la cuenta Fecha Coste total CostType1 CostType2 CostType3 CostType4 CostType5 CostType6 CostType7 CostType8 CostType9 CostType10 CostType11 CostType12 CostType13
Este método está más desnormalizado y puede crear hasta 6 millones de registros por mes ( 200k * N days in month
), o aproximadamente 72 millones por año. Es mucho menos que el primer método, sin embargo, si la compañía decide un nuevo Tipo de costo en el futuro, será necesario agregar otra columna de base de datos.
De los dos métodos, ¿cuál prefiere? ¿Por qué? ¿Hay alguna otra alternativa en la que puedas pensar que manejaría esto mejor?
Estoy más interesado en informar sobre el rendimiento, tanto informes resumidos como detallados. El trabajo que repartirá los costos sobre las cuentas se ejecutará todas las noches cuando no haya nadie cerca. Una preocupación secundaria es el tamaño de la base de datos. La base de datos existente ya tiene casi 300 GB, y creo que el espacio en el disco es de alrededor de 500 GB.
La base de datos es SQL Server 2005
Respuestas:
Mil millones de registros al año no es mucho.
Con la partición (por tipo de costo, tal vez) y el archivo es manejable.
El número de elementos de datos para almacenar sigue siendo 200k * 13 * N.Como columnas, obtendrá menos filas por página y ocupará más espacio que las filas. Puede ganar si "CostType1" no es un tipo de datos de longitud fija, pero es marginal.
"BESO" como dicen
fuente
Si bien su diseño ciertamente puede marcar una diferencia de día o de noche, en este caso me enfocaría más en los índices, incluida la cobertura de los índices según sea necesario. También miraría algunas de las herramientas que SQL Server le brinda para manejar tablas muy grandes, como el particionamiento de tablas.
Piénselo de esta manera, a pesar de que hay 80 mil millones de registros en la tabla, con una indexación adecuada, los que realmente le interesan en cualquier punto dado se agruparán físicamente en el disco. Debido a la forma en que se organizan los datos en el servidor SQL, los datos divididos por límites de índice también pueden estar en otra tabla porque no tiene que leer toda la tabla para obtener lo que necesita.
Si también elige particionar la tabla, puede mejorar el tiempo de acceso y el tiempo de inserción.
fuente
Me normalizaría. Realizamos la contabilidad de costos para la rentabilidad de la cuenta del cliente en un banco y generamos más de 250 millones de filas de costos individuales utilizando cientos de factores que se asignaron por centro de costos o por libro mayor o por varias otras técnicas en millones de cuentas cada mes.
Por ejemplo, el costo total del servicio de los cajeros automáticos se dividió entre las cuentas que habían usado cajeros automáticos en función de la cantidad relativa de uso. Entonces, si $ 1 millón se gastó en el mantenimiento de cajeros automáticos y solo 5 clientes lo usaron una vez cada uno y un cliente lo usó 5 veces, entonces ese cliente le costó al banco $ .5m y los otros clientes le costaron al banco $ .1m cada uno. Otros controladores pueden ser mucho más complejos.
En última instancia, probablemente encontrará que es escaso (ciertas cuentas no obtienen costos de ciertas fuentes / controladores) y algunas cuentas no obtienen nada. En un modelo normalizado, esas filas no existen. En el modelo desnormalizado, la fila existe, con algunas columnas vacías. Además, en un modelo normalizado disperso, debería ver una mejora en el rendimiento, ya que la existencia de una fila suele ser más rápida de verificar (con un índice de cobertura en CostType) que verificar todas las filas con un valor no NULL en un "depósito" particular (incluso con índices en cada columna de cantidad, que puede ver que comienza a ser muy derrochador).
fuente
Independientemente del beneficio de rendimiento, definitivamente estaría a favor de la opción 1. La opción 2 sería robarle a Peter para pagarle a Paul, en mi opinión.
fuente
Iría con la opción 1, y luego, si la velocidad de los informes se convertía en un problema en el futuro, también agregaría la tabla 2 y la completaría en una base de datos de informes en algún tipo de proceso automatizado durante la noche / pico.
También podría considerar acumular la estructura de la tabla 2 diaria en acumulaciones adicionales semanales, mensuales, trimestrales y anuales si se justifica.
Pero, como dije, también elegiría almacenar los datos 'en bruto' en forma adecuada (normalizada).
fuente
Teniendo en cuenta los volúmenes que mencionas, elegiría la segunda opción, pero sin TotalCost. Se podría decir que todavía está normalizado.
Editar: como alternativa, y según sus requisitos y el tamaño del AccountId, también podría considerar lo siguiente:
Con ese diseño, aún puede agregar un TotalCost desnormalizado a la primera tabla y volver a calcularlo todas las noches, lo que permite ejecutar algunos informes solo en la primera tabla.
fuente
TotalCost
allí porque la mayoría de los informes se resumen, y pensé que sería más rápido consultar un solo valor que agregar 13 valores diferentes.En realidad, debe dividir la primera tabla en dos tablas para poder usar una subconsulta y seleccionar la segunda fila como una columna, o muchas columnas. es más flexible de esa manera y por eso, puede obtener un resultado como el segundo más fácilmente.
fuente