sql >> Base de Datos >  >> RDS >> Mysql

base de datos de diseño relacionada con el atributo de tiempo

Aquí hay un modelo para lograr su requisito declarado.

Enlace al modelo de datos de serie temporal

Enlace a notación IDEF1X para aquellos que no están familiarizados con el Estándar de modelado relacional.

  • Normalizado a 5NF; sin columnas duplicadas; sin anomalías de actualización, sin nulos.

  • Cuando cambia el estado de un producto, simplemente inserte una fila en ProductStatus, con la fecha y hora actual. No es necesario tocar las filas anteriores (que eran verdaderas y siguen siendo verdaderas). No hay valores ficticios que las herramientas de informes (aparte de su aplicación) tengan que interpretar.

  • DateTime es la fecha y hora real en la que el producto se colocó en ese estado; el "De", por así decirlo. El "Hasta" se deriva fácilmente:es el DateTime de la fila siguiente (DateTime> "From") para el Producto; donde no existe, el valor es el DateTime actual (use ISNULL).

El primer modelo está completo; (ProductId, DateTime) es suficiente para proporcionar unicidad para la clave principal. Sin embargo, dado que solicita velocidad para ciertas condiciones de consulta, podemos mejorar el modelo a nivel físico y proporcionar:

  • Un índice (ya tenemos el índice PK, por lo que lo mejoraremos primero, antes de agregar un segundo índice) para admitir consultas cubiertas (aquellas basadas en cualquier disposición de { ProductId | DateTime | Status } pueden ser proporcionadas por el índice, sin tener para ir a las filas de datos). Lo que cambia la relación Estado::EstadoProducto de No identificable (línea discontinua) a Tipo identificativo (línea continua).

  • El arreglo PK se elige sobre la base de que la mayoría de las consultas serán Series temporales, según Producto⇢FechaHora⇢Estado.

  • El segundo índice se proporciona para mejorar la velocidad de las consultas según el estado.

  • En el Arreglo Alternativo, eso se invierte; es decir, principalmente queremos el estado actual de todos los Productos.

  • En todas las versiones de ProductStatus, la columna DateTime en el índice secundario (no el PK) es DESCENDENTE; el más reciente es el primero.

He proporcionado la discusión que solicitó. Por supuesto, debe experimentar con un conjunto de datos de tamaño razonable y tomar sus propias decisiones. Si hay algo aquí que no entiende, por favor pregunte y lo ampliaré.

Respuestas a los comentarios

Informar todos los productos con estado actual de 2

SELECT  ProductId,
        Description
    FROM  Product       p,
          ProductStatus ps
    WHERE p.ProductId = ps.ProductId  -- Join
    AND   StatusCode  = 2             -- Request
    AND   DateTime    = (             -- Current Status on the left ...
        SELECT MAX(DateTime)          -- Current Status row for outer Product
            FROM  ProductStatus ps_inner
            WHERE p.ProductId = ps_inner.ProductId
            )
  • ProductId está indexado, columna inicial, ambos lados

  • DateTime en Indexado, 2.ª columna en la opción de consulta cubierta

  • StatusCode está indexado, 3.ª columna en la opción de consulta cubierta

  • Desde StatusCode en el Índice está DESCENDIENDO, solo se requiere una búsqueda para satisfacer la consulta interna

  • las filas se requieren al mismo tiempo, para una consulta; están muy juntos (debido al índice agrupado); casi siempre en la misma página debido al tamaño de fila corto.

Esto es SQL ordinario, una subconsulta, que utiliza la potencia del motor SQL, el procesamiento de conjuntos relacionales. Es el único método correcto , no hay nada más rápido, y cualquier otro método sería más lento. Cualquier herramienta de informes producirá este código con unos pocos clics, sin escribir.

Dos fechas en ProductStatus

Columnas como DateTimeFrom y DateTimeTo son errores graves. Vamos a tomarlo en orden de importancia.

  1. Es un gran error de normalización. "DateTimeTo" se deriva fácilmente del único DateTime de la siguiente fila; por lo tanto, es redundante, una columna duplicada.

    • La precisión no entra en juego:eso se resuelve fácilmente en virtud del tipo de datos (DATE, DATETIME, SMALLDATETIME). Mostrar un segundo, un microsegundo o un nanosegundo menos es una decisión comercial; no tiene nada que ver con los datos que se almacenan.
  2. La implementación de una columna DateTo es un duplicado del 100% (de DateTime de la siguiente fila). Esto ocupa el doble de espacio en disco . Para una mesa grande, eso sería un importante desperdicio innecesario.

  3. Dado que es una fila corta, necesitará el doble de E/S lógicas y físicas para leer la tabla, en cada acceso.

  4. Y el doble de espacio en caché (o dicho de otra manera, solo cabría la mitad de las filas en cualquier espacio de caché dado).

  5. Al introducir una columna duplicada, ha introducido la posibilidad de error (el valor ahora se puede derivar de dos maneras:de la columna DateTimeTo duplicada o de DateTimeFrom de la fila siguiente).

  6. Esta también es una anomalía de actualización . Cuando actualiza cualquier DateTimeFrom, se debe recuperar el DateTimeTo de la fila anterior (no es un gran problema, ya que está cerca) y Actualizarse (un gran problema, ya que es un verbo adicional que se puede evitar).

  7. "Más corto" y "atajos de codificación" son irrelevantes, SQL es un lenguaje de manipulación de datos engorroso, pero SQL es todo lo que tenemos (Simplemente trata con ello). Cualquiera que no pueda codificar una subconsulta realmente no debería estar codificando. Cualquiera que duplique una columna para aliviar la "dificultad" de codificación menor realmente no debería estar modelando bases de datos.

Tenga en cuenta que si se mantiene la regla de orden superior (Normalización), se elimina todo el conjunto de problemas de orden inferior.

Piense en términos de conjuntos

  • Cualquiera que tenga "dificultades" o experimente "dolor" al escribir SQL simple está paralizado en el desempeño de su función laboral. Por lo general, el desarrollador no pensar en términos de conjuntos y la base de datos relacional es un modelo orientado a conjuntos .

  • Para la consulta anterior, necesitamos el DateTime actual; ya que ProductStatus es un conjunto de Estados del producto en orden cronológico, simplemente necesitamos el último, o MAX(DateTime) del conjunto perteneciente al Producto.

  • Ahora veamos algo supuestamente "difícil", en términos de conjuntos . Para un informe de la duración que cada producto ha estado en un estado particular:DateTimeFrom es una columna disponible y define el corte horizontal, un sub conjunto (podemos excluir filas anteriores); DateTimeTo es el primero del sub conjunto de los estados del producto.

SELECT               ProductId,
                     Description,
        [DateFrom] = DateTime,
        [DateTo]   = (
        SELECT MIN(DateTime)                        -- earliest in subset
            FROM  ProductStatus ps_inner
            WHERE p.ProductId = ps_inner.ProductId  -- our Product
            AND   ps_inner.DateTime > ps.DateTime   -- defines subset, cutoff
            )
    FROM  Product       p,
          ProductStatus ps
    WHERE p.ProductId = ps.ProductId 
    AND   StatusCode  = 2             -- Request
  • Pensar en términos de obtener la siguiente fila está orientado a filas, no Procesamiento orientado a conjuntos. Paralizante, cuando se trabaja con una base de datos orientada a conjuntos. Deje que Optimiser haga todo eso por usted. Verifique su SHOWPLAN, esto se optimiza maravillosamente.

  • Incapacidad para pensar en conjuntos , por lo que limitarse a escribir solo consultas de un solo nivel, no es una justificación razonable para:implementar duplicación masiva y anomalías de actualización en la base de datos; malgastar recursos en línea y espacio en disco; garantizando la mitad del rendimiento. Mucho más barato aprender a escribir subconsultas SQL simples para obtener datos fácilmente derivados.