Prueba funcional del metaproyecto | Habilitar la optimización de escaneo de PrestoDB y Aria

Vista rápida

El proyecto Aria de PrestoDB lanzó un conjunto de funciones experimentales en 2020 para mejorar el rendimiento del escaneo en tablas (conectadas a través de conectores Hive y almacenando datos en formato ORC).

En este artículo, realizaremos una prueba básica de estas nuevas funciones en un entorno de prueba PrestoDB basado en Docker. [1]

Pronto

Presto es un motor de ejecución de SQL capaz de procesamiento paralelo masivo (MPP). El motor de ejecución está separado del almacén de datos, y el proyecto contiene una gran cantidad de complementos (también conocidos como conectores) que proporcionan datos consultados al motor de Presto. Una vez que se leen los datos en el almacén de datos, se entregan a Presto para realizar operaciones de consulta, como uniones y agregaciones de datos. Esta arquitectura desacoplada de almacenamiento y ejecución de datos permite que una sola instancia de Presto consulte múltiples fuentes de datos, proporcionando una capa de consulta federada muy poderosa.

Presto tiene muchos conectores disponibles y la comunidad contribuye periódicamente con nuevos conectores para acceder al almacén de datos.

Conector de colmena

El conector Hive generalmente se considera el conector estándar para Presto. Por lo general, lo usamos para conectarnos a Hive Metastore para obtener información de metadatos sobre las tablas definidas en Metastore. Los datos generalmente se almacenan en HDFS o S3, y Metastore proporciona información sobre dónde y en qué formato se almacenan los archivos; el formato ORC es el más utilizado, pero también se admiten otros formatos como Avro y Parquet. El conector de Hive permite que el motor de Presto escanee datos de HDFS/S3 en el motor en paralelo para ejecutar consultas. El formato ORC es un formato de almacenamiento de datos muy estándar y común, que puede proporcionar una buena relación de compresión y rendimiento.

Dos servicios principales para ejecutar consultas

Presto tiene dos servicios principales para ejecutar consultas: un coordinador responsable del análisis de consultas y la programación de tareas, y varios trabajadores responsables de ejecutar consultas en paralelo. En teoría, el Coordinador también puede actuar como Trabajador, pero este no es el caso en un entorno de producción. Como estamos probando Presto aquí, solo usaremos un nodo, tanto como Coordinador como como Trabajador, por conveniencia. [2]

Usaremos un solo contenedor Docker para esta prueba de Presto. Haga clic para ver la documentación de implementación, un ejemplo de cómo implementar una implementación de Presto de un solo nodo se encuentra al final de la documentación.

Así es como Presto ejecuta una consulta:

Primero, el coordinador de Presto analiza la declaración de consulta para formular un plan de ejecución (a continuación se proporcionará un ejemplo). Una vez desarrollado el plan, se divide en fases (o fragmentos), cada una de las cuales realiza una serie de operaciones, es decir, funciones específicas que utiliza el motor para ejecutar la consulta. Los planes de ejecución generalmente comienzan con un conector que escanea en busca de datos, luego realiza una serie de operaciones como el filtrado de datos, la agregación parcial y el intercambio de datos entre los nodos de trabajo de Presto para realizar uniones de datos y la agregación final de datos, etc. Todas estas etapas se dividen en múltiples splits, que son unidades de ejecución paralelas en Presto. Los trabajadores ejecutan una cantidad configurable de fragmentos en paralelo para lograr el resultado deseado. Todos los datos del motor se guardan en la memoria (siempre que no se supere el umbral de capacidad del clúster).

El conector de Hive (y todos los demás conectores) es responsable de dividir el conjunto de datos de entrada en varios fragmentos para que Presto los lea en paralelo. Como optimización, el motor de Presto informará al conector del predicado utilizado en la consulta y la columna seleccionada, lo que se denomina inserción de predicado, lo que permite que el conector del motor de Presto filtre datos innecesarios antes, que es el tema central de este artículo.

Para demostrar la inserción de predicados, veamos una consulta básica: contar el número de filas elegibles en una tabla de datos. Nuestros ejemplos de consulta se basan en la tabla de datos de elementos de línea del conjunto de datos de referencia TPC-H. Hay alrededor de 600 millones de filas en la tabla de elementos de línea de TPC-H, y sus valores de campo de fecha de envío están entre 1992 y 1998. La siguiente instrucción de consulta es un predicado de filtro para las condiciones establecidas de la tabla de datos de elementos de línea y filtra las filas de datos cuyo campo de fecha de envío es 1992. Primero observemos el plan de consulta ejecutando el comando EXPLAIN sin habilitar el atributo de sesión mejorada de Aria:

presto:tpch> EXPLAIN (TYPE DISTRIBUTED) SELECT COUNT(shipdate) FROM lineitem WHERE shipdate BETWEEN DATE '1992-01-01' AND DATE '1992-12-31';

Fragment 0 [SINGLE]
    Output layout: [count]
    Output partitioning: SINGLE []
    Stage Execution Strategy: UNGROUPED_EXECUTION
    - Output[_col0] => [count:bigint]
            _col0 := count
        - Aggregate(FINAL) => [count:bigint]
                count := ""presto.default.count""((count_4))
            - LocalExchange[SINGLE] () => [count_4:bigint]
                - RemoteSource[1] => [count_4:bigint]

Fragment 1 [SOURCE]
    Output layout: [count_4]
    Output partitioning: SINGLE []
    Stage Execution Strategy: UNGROUPED_EXECUTION
    - Aggregate(PARTIAL) => [count_4:bigint]
            count_4 := ""presto.default.count""((shipdate))
       -ScanFilter[table = TableHandle {
   connectorId='hive', connectorHandle='HiveTableHandle{
   schemaName=tpch, tableName=lineitem, analyzePartitionValues=Optional.empty}', layout='Optional[tpch.lineitem{
   domains={
   shipdate=[ [[1992-01-01, 1992-12-31]] ]}}]'}, grouped = false, filterPredicate = shipdate BETWEEN (DATE 1992-01-01) AND (DATE 1992-12-31)] => [shipdate:date]
                Estimates: {
   rows: 600037902 (2.79GB), cpu: 3000189510.00, memory: 0.00, network: 0.00}/{
   rows: ? (?), cpu: 6000379020.00, memory: 0.00, network: 0.00}
                LAYOUT: tpch.lineitem{
   domains={
   shipdate=[ [[1992-01-01, 1992-12-31]] ]}}
                shipdate := shipdate:date:10:REGULAR

El plan de consulta se lee en orden ascendente, comenzando desde el Fragmento 1, escanea la tabla de elementos de línea en paralelo, usa un predicado para filtrar la columna de fecha de envío, luego realiza una agregación parcial en cada fragmento y cambia ese resultado parcial a la siguiente etapa Fragmento 0 para realizar la agregación final y luego enviar el resultado al cliente. El proceso del plan de consulta se muestra en la siguiente figura: (La línea horizontal cerca de la parte inferior de la figura indica qué código se ejecuta en el conector de Hive y qué código se ejecutado en el motor Presto.)
inserte la descripción de la imagen aquí

¡Ahora vamos a ejecutar esta consulta!

presto:tpch> SELECT COUNT(shipdate) FROM lineitem WHERE shipdate BETWEEN DATE '1992-01-01' AND DATE '1992-12-31';
  _col0  
----------
 76036301
(1 row)

Query 20200609_154258_00019_ug2v4, FINISHED, 1 node
Splits: 367 total, 367 done (100.00%)
0:09 [600M rows, 928MB] [63.2M rows/s, 97.7MB/s]

Vemos que la tabla de elementos de línea contiene más de 76 millones de filas con la columna de fecha de envío valorada en 1992. Ejecutar esta consulta tomó alrededor de 9 segundos, procesando un total de 600 millones de filas de datos.

Ahora activemos las propiedades de sesión pushdown_subfields_enabled y hive.pushdown_filter_enabled para habilitar la función Aria, veamos cómo ha cambiado el plan de consulta:

presto:tpch> SET SESSION pushdown_subfields_enabled=true;
SET SESSION
presto:tpch> SET SESSION hive.pushdown_filter_enabled=true;
SET SESSION
presto:tpch> EXPLAIN (TYPE DISTRIBUTED) SELECT COUNT(shipdate) FROM lineitem WHERE shipdate BETWEEN DATE '1992-01-01' AND DATE '1992-12-31';
Fragment 0 [SINGLE]
    Output layout: [count]
    Output partitioning: SINGLE []
    Stage Execution Strategy: UNGROUPED_EXECUTION
    - Output[_col0] => [count:bigint]
            _col0 := count
        - Aggregate(FINAL) => [count:bigint]
                count := ""presto.default.count""((count_4))
            - LocalExchange[SINGLE] () => [count_4:bigint]
                - RemoteSource[1] => [count_4:bigint]

Fragment 1 [SOURCE]
    Output layout: [count_4]
    Output partitioning: SINGLE []
    Stage Execution Strategy: UNGROUPED_EXECUTION
    - Aggregate(PARTIAL) => [count_4:bigint]
            count_4 := ""presto.default.count""((shipdate))
        - TableScan[TableHandle {
   connectorId='hive', connectorHandle='HiveTableHandle{
   schemaName=tpch, tableName=lineitem, analyzePartitionValues=Optional.empty}', layout='Optional[tpch.lineitem{
   domains={
   shipdate=[ [[1992-01-01, 1992-12-31]] ]}}]'}, grouped = false] => [shipdate:date]
                Estimates: {
   rows: 540034112 (2.51GB), cpu: 2700170559.00, memory: 0.00, network: 0.00}
                LAYOUT: tpch.lineitem{
   domains={
   shipdate=[ [[1992-01-01, 1992-12-31]] ]}}
                shipdate := shipdate:date:10:REGULAR
                    :: [[1992-01-01, 1992-12-31]]

Nota: El cambio principal en el plan de consulta se encuentra en la parte inferior, que es la inclusión de la columna de fecha de envío en la operación de TableScan. El conector ha recibido una condición predicada en la columna de fecha de envío: un valor entre 1992-01-01 y 1992-12-31. Como se muestra en la figura a continuación, este predicado se envía al conector, lo que elimina la necesidad de que el motor de consultas filtre estos datos.
inserte la descripción de la imagen aquí

¡Ejecutemos la consulta de nuevo!

presto:tpch> SELECT COUNT(shipdate) FROM lineitem WHERE shipdate BETWEEN DATE '1992-01-01' AND DATE '1992-12-31';
  _col0  
----------
 76036301
(1 row)

Query 20200609_154413_00023_ug2v4, FINISHED, 1 node
Splits: 367 total, 367 done (100.00%)
0:05 [76M rows, 928MB] [15.5M rows/s, 189MB/s]

Después de ejecutar la consulta, obtuvimos los mismos resultados, pero el tiempo de consulta se redujo casi a la mitad y, lo que es más importante, ¡la consulta solo analizó 76 millones de filas! El conector ya aplica predicados a la columna de fecha de envío en lugar de permitir que el motor maneje los predicados, lo que ahorra ciclos de CPU, lo que a su vez acelera las consultas. Puede ser diferente para diferentes consultas y conjuntos de datos, pero si está consultando archivos ORC a través del conector de Hive, definitivamente vale la pena probar esta solución.

Autor del artículo: Adam Shook El texto original fue publicado en el blog personal del autor el 15 de junio de 2020: http://datacatessen.com

Consulte
[1] Para obtener más información sobre las capacidades del proyecto Aria, puede consultar la parte inferior del artículo https://engineering.fb.com/2019/06/10/data-infrastructure/aria-presto/
[2 ] Para más información Para detalles como la instalación, puede consultar el documento al final del artículo https://prestodb.io/docs/current/

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/5904778/blog/5567178
Recomendado
Clasificación