Balanceo de lecturas y escrituras en la base de datos

Balanceo de lecturas y escrituras en la base de datos
En el anterior el artículo He describí la concepción y la implementación de una base de datos construida en función de funciones, no de tablas y campos como en las bases de datos relacionales. Se presentaron numerosos ejemplos que mostraban las ventajas de este enfoque en comparación con el clásico. Muchos los consideraron insuficientemente convincentes.

En este artículo, mostraré cómo tal concepción permite equilibrar rápida y cómodamente la escritura y la lectura en la base de datos sin ningún cambio en la lógica de funcionamiento. Funcionalidades similares han intentado implementarse en los sistemas de gestión de bases de datos comerciales modernos (en particular, Oracle y Microsoft SQL Server). Al final del artículo mostraré que lo que lograron no es muy satisfactorio, por decirlo de manera suave.

Descripción

Al igual que antes, para una mejor comprensión comenzaré la descripción con ejemplos. Supongamos que necesitamos implementar la lógica que retornará una lista de departamentos con el número de empleados en ellos y su salario total.

En la base de datos funcional, esto se vería de la siguiente manera:

CLASS Departamento ‘Departamento’;
name ‘Nombre’ = DATA STRING[100] (Departamento);

CLASS Employee 'Empleado';
department 'Departamento' = DATA Department (Employee);
salary 'Salario' = DATA NUMERIC[10,2] (Employee);

countEmployees 'Número de empleados' (Department d) = 
    AGRUPAR SUMA 1 SI departamento(Empleado e) = d;
salarySum 'Salario total' (Department d) = 
    AGRUPAR SUM salary(Empleado e) SI departamento(e) = d;

SELECT name(Department d), countEmployees(d), salarySum(d);

La complejidad de ejecutar esta consulta en cualquier SGBD será equivalente a O(número de empleados), ya que para este cálculo se debe escanear toda la tabla de empleados y luego agruparlos por departamento. También habrá un pequeño suplemento (considerando que hay muchos más empleados que departamentos) dependiendo del plan elegido. O(log número de empleados) o O(número de departamentos) para la agrupación y otros aspectos.

Es evidente que los costos de ejecución pueden variar entre diferentes SGBD, pero la complejidad no cambiará de ninguna manera.

En la implementación propuesta, la base de datos funcional formará una subconsulta que calculará los valores necesarios por departamento y luego realizará un JOIN con la tabla de departamentos para obtener el nombre. Sin embargo, al declarar cada función, hay la posibilidad de establecer un marcador especial MATERIALIZED. El sistema creará automáticamente el campo correspondiente para cada una de estas funciones. Al cambiar el valor de la función, el campo también cambiará en la misma transacción. Al acceder a esta función, se hará referencia al campo ya calculado.

En particular, si se establece MATERIALIZED para las funciones conteoEmpleados y sumaSalarial, entonces se agregarán dos campos a la tabla con la lista de departamentos, donde se almacenará la cantidad de empleados y su salario total. Ante cualquier cambio en los empleados, sus salarios o su pertenencia a departamentos, el sistema actualizará automáticamente los valores de estos campos. La consulta mencionada anteriormente se dirigirá directamente a estos campos y se ejecutará en O(número de departamentos).

¿Cuáles son las restricciones? Solo una: esta función debe tener un número finito de entradas para las cuales su valor está definido. De lo contrario, no será posible construir una tabla que almacene todos sus valores, ya que no puede haber una tabla con un número infinito de filas.

Ejemplo:

employeesCount 'Número de empleados con salario > N' (Departamento d, NUMERIC[10,2] N) = 
    SUMA GRUPO salario(Empleado e) SI departamento(e) = d Y salario(e) > N;

Esta función está definida para un número infinito de valores del número N (por ejemplo, cualquier valor negativo es válido). Por lo tanto, no se le puede aplicar MATERIALIZED. Así, esta es una restricción lógica y no técnica (es decir, no porque no hayamos podido implementarla). Aparte de eso, no hay restricciones. Se pueden usar agrupaciones, ordenamientos, AND y OR, PARTITION, recursiones, etc.

Por ejemplo, en el ejercicio 2.2 del artículo anterior se puede aplicar MATERIALIZED a ambas funciones:

comprado 'Comprado' (Cliente c, Producto p, ENTERO y) = 
    SUMA DE GRUPO suma(Detalle d) SI 
        cliente(pedido(d)) = c Y 
        producto(d) = p Y 
        extraerAño(fecha(pedido(d))) = y MATERIALIZADO;
calificación 'Calificación' (Cliente c, Producto p, ENTERO y) = 
    PARTICIÓN SUMA 1 ORDEN DESC comprado(c, p, y), p POR c, y MATERIALIZADO;
SELECCIONAR nombreContacto(Cliente c), nombre(Producto p) DONDE calificación(c, p, 1997) < 3;

El sistema creará automáticamente una tabla con claves de tipo Cliente, Producto y ENTERO, añadirá dos campos y actualizará los valores de esos campos con cualquier cambio. En futuras referencias a estas funciones, no se calcularán, sino que se leerán los valores de los campos correspondientes.

Con este mecanismo, se puede, por ejemplo, prescindir de recursiones (CTE) en las consultas. En particular, consideremos grupos que forman un árbol mediante la relación child/parent (cada grupo tiene un enlace a su padre):

parent = DATA Group (Grupo);

En la base de datos funcional, se puede definir la lógica de las recursiones de la siguiente manera:

nivel (Grupo hijo, Grupo padre) = RECURSION 1l SI hijo ES Grupo Y padre == hijo
                                                             PASO 2l SI padre == padre($parent);
esPadre (Grupo hijo, Grupo padre) = VERDADERO SI nivel(hijo, padre) MATERIALIZADO;

Dado que para la función esPadre se ha asignado MATERIALIZED, se creará una tabla con dos claves (grupos), donde el campo esPadre será verdadero solo si la primera clave es un descendiente de la segunda. La cantidad de registros en esta tabla será igual al número de grupos multiplicado por la profundidad media del árbol. Si se necesita, por ejemplo, contar el número de descendientes de un grupo específico, se puede referirse a esta función:

childrenCount (Grupo g) = SUMA DEL GRUPO 1 SI esPadre(Grupo hijo, g);

No habrá CTE en la consulta SQL. En su lugar, habrá un simple GROUP BY.

A través de este mecanismo también se puede realizar fácilmente la desnormalización de la base de datos si es necesario:

CLASS Pedido 'Pedido';
fecha 'Fecha' = DATA DATE (Orden);

CLASE OrderDetail 'Línea de pedido';
pedido 'Pedido' = DATOS Order (OrderDetail);
fecha 'Fecha' (OrderDetail d) = fecha(order(d)) ÍNDICE MATERIALIZADO;

Al llamar a la función Muestra la fecha y hora actuales del sistema. para la línea de pedido, se realizará una lectura de la tabla con las líneas de pedidos en el campo que tiene un índice. Cuando se cambie la fecha del pedido, el sistema recalculará automáticamente la fecha desnormalizada en la línea.

Ventajas

¿Para qué se necesita todo este mecanismo? En las bases de datos tradicionales, sin reescribir consultas, un desarrollador o DBA solo puede modificar índices, establecer estadísticas y sugerir al planificador de consultas cómo ejecutarlas (y las HINTs solo están disponibles en bases de datos comerciales). Por mucho esfuerzo que realicen, no podrán ejecutar la primera consulta del artículo en O (número de departamentos) sin modificar las consultas y sin escribir triggers. En el esquema propuesto, en la etapa de desarrollo, no es necesario preocuparse por la estructura de almacenamiento de datos ni por qué agregaciones utilizar. Todo esto se puede cambiar en tiempo real durante la explotación.

En la práctica, esto se ve de la siguiente manera. Algunas personas desarrollan directamente la lógica basada en la tarea establecida. No se ocupan de los algoritmos y su complejidad, ni de los planes de ejecución, ni de los tipos de joins, ni de ningún otro componente técnico. Estas personas son más analistas de negocios que desarrolladores. Luego, todo esto pasa a pruebas o explotación. Se activa el registro de consultas largas. Cuando se detecta una consulta lenta, otras personas (más técnicas, en esencia DBA) toman la decisión de activar MATERIALIZED en alguna función intermedia. De este modo, se ralentiza un poco la escritura (pues se requiere la actualización de un campo adicional en la transacción). Sin embargo, se acelera significativamente no solo esta consulta, sino también todas las demás que utilizan esta función. Al mismo tiempo, la decisión sobre qué función materializar se toma de manera relativamente sencilla. Dos parámetros principales: el número de posibles valores de entrada (exactamente tantas entradas habrá en la tabla correspondiente) y con qué frecuencia se utiliza en otras funciones.

Análogos.

En las bases de datos comerciales modernas, existen mecanismos similares: MATERIALIZED VIEW con FAST REFRESH (Oracle) y INDEXED VIEW (Microsoft SQL Server). En PostgreSQL, el MATERIALIZED VIEW no puede actualizarse en transacciones, solo a petición (y además con restricciones bastante estrictas), así que no lo consideraremos. Pero tienen varios problemas que limitan considerablemente su uso.

En primer lugar, se puede activar la materialización solo si ya se ha creado una vista normal. De lo contrario, será necesario reescribir otras consultas que accedan a la nueva vista creada para utilizar esta materialización. O dejar todo como está, pero sería al menos ineficiente, dado que hay ciertos datos ya precalculados que muchas consultas no utilizan siempre y los recalculan.

En segundo lugar, tienen una enorme cantidad de restricciones:

Oracle

5.3.8.4 Restricciones generales sobre Fast Refresh

La consulta definitoria de la vista materializada está restringida de la siguiente manera:

  • La vista materializada no debe contener referencias a expresiones no repetitivas como SYSDATE y ROWNUM.
  • La vista materializada no debe contener referencias a RAW o LONG RAW tipos de datos.
  • No puede contener una SELECCIONAR subconsulta de lista.
  • No puede contener funciones analíticas (por ejemplo, RANK) en la SELECCIONAR cláusula.
  • No puede hacer referencia a una tabla en la que se defina un XMLIndex índice.
  • No puede contener una MODELO cláusula.
  • No puede contener una cláusula HAVING con una subconsulta. No puede contener consultas anidadas que tengan
  • CUALQUIER TODOS, , o[START WITH …] CONNECT BY NOT EXISTS.
  • No puede contener una No puede contener múltiples tablas detalle en diferentes sitios. cláusula.
  • Sobre
  • las vistas materializadas no pueden tener tablas detalle remotas. COMMIT Las vistas materializadas anidadas deben tener un join o agregación.
  • Las vistas de unión materializadas y las vistas de agregación materializadas con un
  • GROUP BY no pueden seleccionar de una tabla organizada por índice. 5.3.8.5 Restricciones sobre Fast Refresh en Vistas Materializadas con Solo Uniones

Las consultas definitorias para vistas materializadas con solo uniones y sin agregados tienen las siguientes restricciones sobre fast refresh:

Todas las restricciones de «

  • Restricciones Generales sobre Fast RefreshNo pueden tener«.
  • cláusulas o agregados. BY no pueden seleccionar de una tabla organizada por índice. Los rowids de todas las tablas en la
  • lista deben aparecer en la FROM lista de la consulta. SELECCIONAR Los registros de vista materializada deben existir con rowids para todas las tablas base en la
  • No se puede crear una vista materializada actualizable rápidamente a partir de múltiples tablas con uniones simples que incluyan una columna de tipo objeto en el FROM Los registros de vista materializada deben existir con rowids para todas las tablas base en la
  • declaración. SELECCIONAR Además, el método de actualización que elijas no será óptimamente eficiente si:

La consulta definitoria utiliza una unión externa que se comporta como una unión interna. Si la consulta definitoria contiene tal unión, considera reescribir la consulta definitoria para contener una unión interna.

  • La
  • lista de la vista materializada contiene expresiones sobre columnas de múltiples tablas. SELECCIONAR 5.3.8.6 Restricciones sobre Fast Refresh en Vistas Materializadas con Agregados

Las consultas definitorias para vistas materializadas con agregados o uniones tienen las siguientes restricciones sobre fast refresh:

Se admite el refresh rápido para ambas

vistas materializadas de DEMANDA, sin embargo, se aplican las siguientes restricciones: las vistas materializadas no pueden tener tablas detalle remotas. COMMIT y las vistas materializadas no pueden tener tablas detalle remotas. Todas las tablas en la vista materializada deben tener registros de vista materializada, y los registros de vista materializada deben: Contener todas las columnas de la tabla referenciada en la vista materializada.

  • Especificar con
    • ROWID
    • INCLUYENDO NUEVAS y VALORES Especificar la SECUENCIA.
    • cláusula si se espera que la tabla tenga una mezcla de inserciones/cargas directas, eliminaciones y actualizaciones. Solo SUMA

  • DESVEST VARIANZA, COUNT, AVG, MAX, son compatibles con fast refresh., MIN y COUNT(*) debe ser especificado.
  • COUNT(*) debe ser especificado.
  • Las funciones agregadas deben ocurrir solo como la parte más externa de la expresión. Es decir, agregados como AVG(AVG(x)) o AVG(x)+ AVG(x) no están permitidos.
  • Para cada agregado como AVG(expr), el correspondiente COUNT(expr) debe estar presente. Oracle recomienda que SUM(expr) se especifique.
  • Si VARIANCE(expr) o STDDEV(expr) se especifica, COUNT(expr) y SUM(expr) debe especificarse. Oracle recomienda que SUM(expr *expr) se especifique.
  • lista de la vista materializada contiene expresiones sobre columnas de múltiples tablas. SELECCIONAR la columna en la consulta definitoria no puede ser una expresión compleja con columnas de múltiples tablas base. Una posible solución a esto es utilizar una vista materializada anidada.
  • lista de la vista materializada contiene expresiones sobre columnas de múltiples tablas. SELECCIONAR la lista debe contener todas BY no pueden seleccionar de una tabla organizada por índice. las columnas.
  • La vista materializada no está basada en una o más tablas remotas.
  • Si usas un tipo de dato CHAR en las columnas de filtro de un registro de vista materializada, los conjuntos de caracteres del sitio maestro y la vista materializada deben ser los mismos. Si la vista materializada tiene uno de los siguientes, entonces la actualización rápida es compatible solo con inserciones DML convencionales y cargas directas.
  • Vistas materializadas con
    • agregados MIN o COUNT(*) Vistas materializadas que tienen
    • pero no SUM(expr) Vistas materializadas sin COUNT(expr)
    • Tal vista materializada se llama una vista materializada solo para inserciones. COUNT(*)

    Una vista materializada con

  • es actualizable rápidamente después de eliminar o realizar declaraciones DML mixtas si no tiene un COUNT(*) o MIN La actualización rápida de max/min después de eliminar o realizar DML mixtos no tiene el mismo comportamiento que el caso solo para inserciones. Se eliminan y recomputan los valores max/min para los grupos afectados. Debes ser consciente de su impacto en el rendimiento. WHERE cláusula.
    Las vistas materializadas con vistas nombradas o subconsultas en la
  • la cláusula pueden actualizarse rápidamente siempre que las vistas puedan combinarse completamente. Para información sobre qué vistas se combinarán, consulta FROM Referencia del Lenguaje SQL de Oracle Database Si no hay uniones externas, puedes tener selecciones y uniones arbitrarias en la.
  • Las vistas agregadas materializadas con uniones externas son actualizables rápidamente después de DML convencionales y cargas directas, siempre que solo se haya modificado la tabla externa. Además, deben existir restricciones únicas en las columnas de unión de la tabla de unión interna. Si hay uniones externas, todas las uniones deben estar conectadas por WHERE cláusula.
  • y deben utilizar el operador de igualdad ( Y) operator.=Para las vistas materializadas con
  • CUBE ROLLUP, , conjuntos de agrupamiento, o concatenación de ellos, se aplican las siguientes restricciones:la lista debe contener un diferenciador de agrupamiento que puede ser un
    • lista de la vista materializada contiene expresiones sobre columnas de múltiples tablas. SELECCIONAR función GROUPING_ID en todas las expresiones o funciones GROUPING, una para cada BY no pueden seleccionar de una tabla organizada por índice. expresión. Por ejemplo, si la la cláusula de la vista materializada es « CUBE(a, b) BY no pueden seleccionar de una tabla organizada por índice. «, entonces la BY no pueden seleccionar de una tabla organizada por índice. la lista debe contener ya «BY no pueden seleccionar de una tabla organizada por índice. GROUPING_ID(a, b)» o « SELECCIONAR GROUPING(a)GROUPING(b)» para que la vista materializada sea actualizable rápidamente.no debe resultar en agrupaciones duplicadas. Por ejemplo, « Y GROUP BY a, ROLLUP(a, b)» no es actualizable rápidamente porque resulta en agrupaciones duplicadas «
    • BY no pueden seleccionar de una tabla organizada por índice. (a), (a, b), Y (a)5.3.8.7 Restricciones sobre la Actualización Rápida de las Vistas Materializadas con UNION ALLLas vistas materializadas con elUNION«.

el operador de conjunto soporta la

REFRESH RÁPIDO , o si se satisfacen las siguientes condiciones: La consulta definitoria debe tener el operador en el nivel superior. El operador no puede estar incrustado dentro de una subconsulta, con una excepción: El

  • puede estar en una subconsulta en la RÁPIDO , o la cláusula siempre que la consulta definitoria tenga la forma

    lista de la vista materializada contiene expresiones sobre columnas de múltiples tablas. RÁPIDO , o SELECT * FROM RÁPIDO , o (vista o subconsulta con FROM ) como en el siguiente ejemplo: CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM customers c WHERE c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM customers c WHERE c.cust_last_name = 'Jones');CREATE MATERIALIZED VIEW unionall_inside_view_mv REFRESH FAST ON DEMAND AS SELECT * FROM view_with_unionall; Ten en cuenta que la vista RÁPIDO , oview_with_unionall

    cumple con los requisitos para actualización rápida.
    

    Cada bloque de consulta en la la consulta debe cumplir con los requisitos de una vista materializada actualizable rápidamente con agregados o una vista materializada actualizable rápidamente con uniones. Los registros de vista materializada apropiados deben crearse en las tablas según lo requerido para el tipo correspondiente de vista materializada actualizable rápidamente.

  • Cada bloque de consulta en el RÁPIDO , o la consulta debe cumplir con los requisitos de una vista materializada refrescable rápida con agregados o una vista materializada refrescable rápida con uniones.

    Los registros de vista materializada apropiados deben ser creados en las tablas según sea necesario para el tipo correspondiente de vista materializada refrescable rápida.
    Tenga en cuenta que la base de datos de Oracle también permite el caso especial de una vista materializada de una sola tabla con uniones únicamente proporcionadas que NUEVAS la columna se haya incluido en el SELECCIONAR listado y en el registro de la vista materializada. Esto se muestra en la consulta definitoria de la vista la consulta debe cumplir con los requisitos de una vista materializada actualizable rápidamente con agregados o una vista materializada actualizable rápidamente con uniones..

  • lista de la vista materializada contiene expresiones sobre columnas de múltiples tablas. SELECCIONAR la lista de cada consulta debe incluir un RÁPIDO , o marcador, y el RÁPIDO , o la columna debe tener un valor único constante numérico o de cadena en cada RÁPIDO , o rama. Además, la columna del marcador debe aparecer en la misma posición ordinal en el SELECCIONAR lista de cada bloque de consulta. Consulte «UNION ALL Marker y Reescritura de Consulta» para más información sobre RÁPIDO , o marcadores.
  • Algunas características como las uniones externas, consultas de vista materializada solo de inserción y tablas remotas no son compatibles con vistas materializadas con RÁPIDO , o. Tenga en cuenta, sin embargo, que las vistas materializadas utilizadas en la replicación, que no contienen uniones ni agregados, pueden actualizarse rápidamente cuando RÁPIDO , o o se utilizan tablas remotas.
  • El parámetro de inicialización de compatibilidad debe establecerse en 9.2.0 o superior para crear una vista materializada que se pueda actualizar rápidamente con RÁPIDO , o.

No quiero ofender a los aficionados de Oracle, pero a juzgar por su lista de restricciones, se da la impresión de que este mecanismo no fue desarrollado en términos generales, utilizando algún modelo, sino por miles de indios, a cada uno de los cuales se le permitió escribir su propia rama, y cada uno hizo lo que pudo. Utilizar este mecanismo para lógica real es como caminar por un campo minado. En cualquier momento se puede activar una mina al caer en una de las restricciones no evidentes. Cómo funciona esto es también una cuestión aparte, pero está fuera del alcance de este artículo.

Microsoft SQL Server

Requisitos Adicionales

Además de las opciones de SET y los requisitos de funciones determinísticas, se deben cumplir los siguientes requisitos:

  • El usuario que ejecuta CREAR ÍNDICE debe ser el propietario de la vista.
  • Cuando crea el índice, la IGNORE_DUP_KEY la opción debe estar establecida en OFF (la configuración predeterminada).
  • Las tablas deben ser referenciadas por nombres de dos partes, schema.tablename en la definición de la vista.
  • Las funciones definidas por el usuario que se referencian en la vista deben ser creadas utilizando la CON UN ESQUEMA DE VINCULACIÓN opción.
  • Cualquier función definida por el usuario que se refiera en la vista debe ser referenciada por nombres de dos partes, <schema>.<function>.
  • La propiedad de acceso a datos de una función definida por el usuario debe ser SIN SQL, y la propiedad de acceso externo debe ser NO.
  • Las funciones del tiempo de ejecución del lenguaje común (CLR) pueden aparecer en la lista de selección de la vista, pero no pueden ser parte de la definición de la clave del índice agrupado. Las funciones CLR no pueden aparecer en la cláusula WHERE de la vista o en la cláusula ON de una operación JOIN en la vista.
  • Las funciones CLR y los métodos de tipos definidos por el usuario CLR utilizados en la definición de la vista deben tener las propiedades establecidas como se muestra en la siguiente tabla.

    Propiedad
    Note

    DETERMINISTA = VERDADERO
    Debe declararse explícitamente como un atributo del método de Microsoft .NET Framework.

    PRECISO = VERDADERO
    Debe declararse explícitamente como un atributo del método de .NET Framework.

    ACCESO A DATOS = SIN SQL
    Determinado estableciendo el atributo DataAccess en DataAccessKind.None y el atributo SystemDataAccess en SystemDataAccessKind.None.

    ACCESO EXTERNO = NO
    Esta propiedad por defecto es NO para las rutinas CLR.

  • La vista debe ser creada utilizando el CON UN ESQUEMA DE VINCULACIÓN opción.
  • La vista debe referenciar únicamente tablas base que están en la misma base de datos que la vista. La vista no puede referenciar otras vistas.
  • La instrucción SELECT en la definición de la vista no debe contener los siguientes elementos de Transact-SQL:

    COUNT
    Funciones de conjunto de filas (OPENDATASOURCE, OPENQUERY, OPENROWSET, Y OPENXML)
    EXTERNAS uniones (IZQUIERDA, DERECHA[START WITH …] CONNECT BY COMPLETA)

    Tabla derivada (definida especificando un SELECCIONAR instrucción en la FROM cláusula)
    Autouniones
    Especificando columnas utilizando SELECCIONAR * o SELECCIONAR .*

    DISTINCT
    DEVS, DEVP, VAR, VARP[START WITH …] CONNECT BY AVG
    Expresión de tabla común (CTE)

    flotante1, text, ntext, image, XML[START WITH …] CONNECT BY filestream columnas
    Subconsulta
    SOBRE cláusula, que incluye funciones de ventana de clasificación o agregación

    Predicados de texto completo (CONTENIDO, FREETEXT)
    VARIANZA función que hace referencia a una expresión anulable
    ORDER BY

    Función de agregado definida por el usuario CLR
    MÁS ALTO
    ROLLUP, , conjuntos de agrupamiento, o concatenación de ellos, se aplican las siguientes restricciones:[START WITH …] CONNECT BY CONJUNTOS DE AGRUPAMIENTO operadores

    MIN, COUNT(*)
    RÁPIDO, EXCEPCIÓN[START WITH …] CONNECT BY INTERSECCIÓN operadores
    MUESTRA DE TABLA

    Variables de tabla
    APLICACIÓN EXTERNA o CROSS APPLY
    PIVOTE, DESPIVOTE

    Conjuntos de columnas sparsas
    Funciones de tabla valoradas en línea (TVF) o funciones de tabla valoradas de múltiples declaraciones (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 La vista indexada puede contener flotante columnas; sin embargo, tales columnas no pueden incluirse en la clave del índice agrupado.

  • Si GROUP BY está presente, la definición de la VISTA debe contener CONTAR_GRANDE(*) y no debe contener cláusula HAVING con una subconsulta.. Estas GROUP BY restricciones son aplicables solo a la definición de vista indexada. Una consulta puede usar una vista indexada en su plan de ejecución incluso si no satisface estas GROUP BY restricciones.
  • Si la definición de la vista contiene una GROUP BY cláusula, la clave del índice único agrupado puede hacer referencia solo a las columnas especificadas en el GROUP BY cláusula.

Aquí se puede ver que los indios no fueron atraídos, ya que decidieron hacerlo bajo el esquema de "hacemos poco, pero bien". Es decir, tienen más minas en el campo, pero su ubicación es más transparente. Lo que más decepciona es esta restricción:

La vista debe referenciar únicamente tablas base que están en la misma base de datos que la vista. La vista no puede referenciar otras vistas.

En nuestra terminología, esto significa que una función no puede llamar a otra función materializada. Esto corta toda la ideología de raíz.
Además, esta restricción (y las siguientes en el texto) reduce drásticamente las opciones de uso:

La instrucción SELECT en la definición de la vista no debe contener los siguientes elementos de Transact-SQL:

COUNT
Funciones de conjunto de filas (OPENDATASOURCE, OPENQUERY, OPENROWSET, Y OPENXML)
EXTERNAS uniones (IZQUIERDA, DERECHA[START WITH …] CONNECT BY COMPLETA)

Tabla derivada (definida especificando un SELECCIONAR instrucción en la FROM cláusula)
Autouniones
Especificando columnas utilizando SELECCIONAR * o SELECCIONAR .*

DISTINCT
DEVS, DEVP, VAR, VARP[START WITH …] CONNECT BY AVG
Expresión de tabla común (CTE)

flotante1, text, ntext, image, XML[START WITH …] CONNECT BY filestream columnas
Subconsulta
SOBRE cláusula, que incluye funciones de ventana de clasificación o agregación

Predicados de texto completo (CONTENIDO, FREETEXT)
VARIANZA función que hace referencia a una expresión anulable
ORDER BY

Función de agregado definida por el usuario CLR
MÁS ALTO
ROLLUP, , conjuntos de agrupamiento, o concatenación de ellos, se aplican las siguientes restricciones:[START WITH …] CONNECT BY CONJUNTOS DE AGRUPAMIENTO operadores

MIN, COUNT(*)
RÁPIDO, EXCEPCIÓN[START WITH …] CONNECT BY INTERSECCIÓN operadores
MUESTRA DE TABLA

Variables de tabla
APLICACIÓN EXTERNA o CROSS APPLY
PIVOTE, DESPIVOTE

Conjuntos de columnas sparsas
Funciones de tabla valoradas en línea (TVF) o funciones de tabla valoradas de múltiples declaraciones (MSTVF)
OFFSET

CHECKSUM_AGG

Se prohíben JOINs EXTERNOS, UNIÓN, ORDER BY y otros. Quizás hubiera sido más fácil indicar qué se puede usar en lugar de lo que no se puede. La lista probablemente sería mucho más corta.

En resumen: un enorme conjunto de restricciones en cada SGBD (comercial, lo señalaré) frente a ninguna (excepto una lógica, no técnica) en la tecnología LGPL. Sin embargo, cabe destacar que implementar este mecanismo en lógica relacional es algo más complicado que en la funcionalidad descrita.

Implementación

¿Cómo funciona? Se utiliza PostgreSQL como "máquina virtual". Dentro hay un algoritmo complejo que se encarga de construir consultas. Aquí código fuente. Y no es solo un gran conjunto de heurísticas con un montón de ifs. Así que, si hay un par de meses para estudiar, pueden intentar entender la arquitectura.

¿Funciona esto de manera efectiva? Suficientemente efectivo. Desafortunadamente, es difícil probarlo. Solo puedo decir que, si consideramos miles de consultas que existen en grandes aplicaciones, en promedio son más eficientes que las de un buen desarrollador. Un excelente programador de SQL puede escribir cualquier consulta de manera más eficiente, pero en mil consultas simplemente no tendrá ni la motivación ni el tiempo para hacerlo. Lo único que puedo presentar ahora como prueba de efectividad es que en la plataforma construida sobre esta base de datos funcionan varios proyectos. Sistemas ERP, que tienen miles de diversas funciones MATERIALIZED, con miles de usuarios y bases de terabytes con cientos de millones de registros, operando en un servidor de dos procesadores común. Sin embargo, cualquier persona interesada puede comprobar/desmentir la efectividad, descargando plataforma y PostgreSQL, activando el registro de consultas SQL y tratando de modificar allí la lógica y los datos.

En los próximos artículos, también hablaré sobre cómo se pueden establecer restricciones en funciones, trabajar con sesiones de cambios y mucho más.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster