¿Cómo se decide el número de pasos del histograma en Estadísticas?


11

¿Cómo se decide el número de pasos del histograma en Estadísticas en SQL Server?

¿Por qué está restringido a 200 pasos a pesar de que mi columna clave tiene más de 200 valores distintos? ¿Hay algún factor decisivo?


Manifestación

Definición de esquema

CREATE TABLE histogram_step
  (
     id   INT IDENTITY(1, 1),
     name VARCHAR(50),
     CONSTRAINT pk_histogram_step PRIMARY KEY (id)
  )

Insertar 100 registros en mi tabla

INSERT INTO histogram_step
            (name)
SELECT TOP 100 name
FROM   sys.syscolumns

Actualizar y verificar las estadísticas

UPDATE STATISTICS histogram_step WITH fullscan

DBCC show_statistics('histogram_step', pk_histogram_step)

Pasos del histograma:

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            1 |          0 |       1 |                   0 |              1 |
|            3 |          1 |       1 |                   1 |              1 |
|            5 |          1 |       1 |                   1 |              1 |
|            7 |          1 |       1 |                   1 |              1 |
|            9 |          1 |       1 |                   1 |              1 |
|           11 |          1 |       1 |                   1 |              1 |
|           13 |          1 |       1 |                   1 |              1 |
|           15 |          1 |       1 |                   1 |              1 |
|           17 |          1 |       1 |                   1 |              1 |
|           19 |          1 |       1 |                   1 |              1 |
|           21 |          1 |       1 |                   1 |              1 |
|           23 |          1 |       1 |                   1 |              1 |
|           25 |          1 |       1 |                   1 |              1 |
|           27 |          1 |       1 |                   1 |              1 |
|           29 |          1 |       1 |                   1 |              1 |
|           31 |          1 |       1 |                   1 |              1 |
|           33 |          1 |       1 |                   1 |              1 |
|           35 |          1 |       1 |                   1 |              1 |
|           37 |          1 |       1 |                   1 |              1 |
|           39 |          1 |       1 |                   1 |              1 |
|           41 |          1 |       1 |                   1 |              1 |
|           43 |          1 |       1 |                   1 |              1 |
|           45 |          1 |       1 |                   1 |              1 |
|           47 |          1 |       1 |                   1 |              1 |
|           49 |          1 |       1 |                   1 |              1 |
|           51 |          1 |       1 |                   1 |              1 |
|           53 |          1 |       1 |                   1 |              1 |
|           55 |          1 |       1 |                   1 |              1 |
|           57 |          1 |       1 |                   1 |              1 |
|           59 |          1 |       1 |                   1 |              1 |
|           61 |          1 |       1 |                   1 |              1 |
|           63 |          1 |       1 |                   1 |              1 |
|           65 |          1 |       1 |                   1 |              1 |
|           67 |          1 |       1 |                   1 |              1 |
|           69 |          1 |       1 |                   1 |              1 |
|           71 |          1 |       1 |                   1 |              1 |
|           73 |          1 |       1 |                   1 |              1 |
|           75 |          1 |       1 |                   1 |              1 |
|           77 |          1 |       1 |                   1 |              1 |
|           79 |          1 |       1 |                   1 |              1 |
|           81 |          1 |       1 |                   1 |              1 |
|           83 |          1 |       1 |                   1 |              1 |
|           85 |          1 |       1 |                   1 |              1 |
|           87 |          1 |       1 |                   1 |              1 |
|           89 |          1 |       1 |                   1 |              1 |
|           91 |          1 |       1 |                   1 |              1 |
|           93 |          1 |       1 |                   1 |              1 |
|           95 |          1 |       1 |                   1 |              1 |
|           97 |          1 |       1 |                   1 |              1 |
|           99 |          1 |       1 |                   1 |              1 |
|          100 |          0 |       1 |                   0 |              1 |
+--------------+------------+---------+---------------------+----------------+

Como podemos ver, hay 53 pasos en el histograma.

Nuevamente insertando unos pocos miles de registros

INSERT INTO histogram_step
            (name)
SELECT TOP 10000 b.name
FROM   sys.syscolumns a
       CROSS JOIN sys.syscolumns b

Actualizar y verificar las estadísticas

UPDATE STATISTICS histogram_step WITH fullscan

DBCC show_statistics('histogram_step', pk_histogram_step)

Ahora los pasos del histograma se reducen a 4 pasos.

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            1 |          0 |       1 |                   0 |              1 |
|        10088 |      10086 |       1 |               10086 |              1 |
|        10099 |         10 |       1 |                  10 |              1 |
|        10100 |          0 |       1 |                   0 |              1 |
+--------------+------------+---------+---------------------+----------------+

Nuevamente insertando unos pocos miles de registros

INSERT INTO histogram_step
            (name)
SELECT TOP 100000 b.name
FROM   sys.syscolumns a
       CROSS JOIN sys.syscolumns b

Actualizar y verificar las estadísticas

UPDATE STATISTICS histogram_step WITH fullscan

DBCC show_statistics('histogram_step', pk_histogram_step) 

Ahora los pasos del histograma se reducen a 3 pasos.

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            1 |          0 |       1 |                   0 |              1 |
|       110099 |     110097 |       1 |              110097 |              1 |
|       110100 |          0 |       1 |                   0 |              1 |
+--------------+------------+---------+---------------------+----------------+

¿Alguien puede decirme cómo se deciden estos pasos?


3
200 fue una elección arbitraria. No tiene nada que ver con cuántos valores distintos tiene en una tabla específica. Si desea saber por qué se eligió 200, tendrá que preguntarle a un ingeniero del equipo SQL Server de la década de 1990, no a sus pares
Aaron Bertrand

1
@AaronBertrand - Gracias ... Entonces, ¿cómo se deciden estos pasos
P ரதீப்

1
No hay decisión El límite superior es 200. Periodo. Bueno, técnicamente, es 201, pero esa es una historia para otro día.
Aaron Bertrand

1
He hecho una pregunta similar sobre las estimaciones intra
paso

Respuestas:


14

Limitaré esta publicación para discutir estadísticas de una sola columna porque ya será bastante larga y le interesa cómo SQL Server agrupa los datos en pasos de histograma. Para las estadísticas de varias columnas, el histograma solo se crea en la columna inicial.

Cuando SQL Server determina que se necesita una actualización de estadísticas, inicia una consulta oculta que lee todos los datos de una tabla o una muestra de los datos de la tabla. Puede ver estas consultas con eventos extendidos. Hay una función llamada StatMandentro de SQL Server que participa en la creación de los histogramas. Para los objetos de estadísticas simples, hay al menos dos tipos diferentes de StatManconsultas (hay consultas diferentes para actualizaciones rápidas de estadísticas y sospecho que la función de estadísticas incrementales en tablas particionadas también usa una consulta diferente).

El primero solo toma todos los datos de la tabla sin ningún filtro. Puede ver esto cuando la tabla es muy pequeña o si reúne estadísticas con la FULLSCANopción:

CREATE TABLE X_SHOW_ME_STATMAN (N INT);
CREATE STATISTICS X_STAT_X_SHOW_ME_STATMAN ON X_SHOW_ME_STATMAN (N);

-- after gathering stats with 1 row in table
SELECT StatMan([SC0]) FROM
(
    SELECT TOP 100 PERCENT [N] AS [SC0] 
    FROM [dbo].[X_SHOW_ME_STATMAN] WITH (READUNCOMMITTED)
    ORDER BY [SC0] 
) AS _MS_UPDSTATS_TBL 
OPTION (MAXDOP 16);

SQL Server elige el tamaño de muestra automático en función del tamaño de la tabla (creo que es tanto el número de filas como las páginas de la tabla). Si una tabla es demasiado grande, el tamaño de la muestra automática cae por debajo del 100%. Esto es lo que obtuve para la misma tabla con 1M de filas:

-- after gathering stats with 1 M rows in table
SELECT StatMan([SC0], [SB0000]) FROM 
(
    SELECT TOP 100 PERCENT [SC0], step_direction([SC0]) over (order by NULL) AS [SB0000] 
    FROM 
    (
        SELECT [N] AS [SC0] 
        FROM [dbo].[X_SHOW_ME_STATMAN] TABLESAMPLE SYSTEM (6.666667e+001 PERCENT) WITH (READUNCOMMITTED) 
    ) AS _MS_UPDSTATS_TBL_HELPER 
    ORDER BY [SC0], [SB0000] 
) AS _MS_UPDSTATS_TBL
OPTION (MAXDOP 1);

TABLESAMPLEestá documentado pero StatMan y step_direction no lo están. aquí SQL Server muestrea alrededor del 66,6% de los datos de la tabla para crear el histograma. Lo que esto significa es que podría obtener un número diferente de pasos de histograma al actualizar estadísticas (sin FULLSCAN) en los mismos datos. Nunca he observado esto en la práctica, pero no veo por qué no sería posible.

Ejecutemos algunas pruebas en datos simples para ver cómo cambian las estadísticas con el tiempo. A continuación hay un código de prueba que escribí para insertar enteros secuenciales en una tabla, recopilar estadísticas después de cada inserción y guardar información sobre las estadísticas en una tabla de resultados. Comencemos simplemente insertando 1 fila a la vez hasta 10000. Banco de pruebas:

DECLARE
@stats_id INT,
@table_object_id INT,
@rows_per_loop INT = 1,
@num_of_loops INT = 10000,
@loop_num INT;

BEGIN
    SET NOCOUNT ON;

    TRUNCATE TABLE X_STATS_RESULTS;

    SET @table_object_id = OBJECT_ID ('X_SEQ_NUM');
    SELECT @stats_id = stats_id FROM sys.stats
    WHERE OBJECT_ID = @table_object_id
    AND name = 'X_STATS_SEQ_INT_FULL';

    SET @loop_num = 0;
    WHILE @loop_num < @num_of_loops
    BEGIN
        SET @loop_num = @loop_num + 1;

        INSERT INTO X_SEQ_NUM WITH (TABLOCK)
        SELECT @rows_per_loop * (@loop_num - 1) + N FROM dbo.GetNums(@rows_per_loop);

        UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN; -- can comment out FULLSCAN as needed

        INSERT INTO X_STATS_RESULTS WITH (TABLOCK)
        SELECT 'X_STATS_SEQ_INT_FULL', @rows_per_loop * @loop_num, rows_sampled, steps 
        FROM sys.dm_db_stats_properties(@table_object_id, @stats_id);
        END;
END;

Para estos datos, el número de pasos del histograma aumenta rápidamente a 200 (primero alcanza el número máximo de pasos con 397 filas), permanece en 199 o 200 hasta que 1485 filas estén en la tabla, luego disminuye lentamente hasta que el histograma solo tiene 3 o 4 pasos. Aquí hay un gráfico de todos los datos:

primer gráfico

Aquí está el histograma para 10k filas:

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1               0           1       0                   1
9999            9997        1       9997                1
10000           0           1       0                   1

¿Es un problema que el histograma solo tenga 3 pasos? Parece que la información se conserva desde nuestro punto de vista. Tenga en cuenta que debido a que el tipo de datos es un INTEGER, podemos calcular cuántas filas hay en la tabla para cada número entero de 1 a 10000. Por lo general, SQL Server también puede resolver esto, aunque hay algunos casos en los que esto no funciona del todo . Ver esta publicación SE para un ejemplo de esto.

¿Qué crees que sucederá si eliminamos una sola fila de la tabla y actualizamos las estadísticas? Idealmente, obtendríamos otro paso de histograma para mostrar que el entero que falta ya no está en la tabla.

DELETE FROM X_SEQ_NUM
WHERE X_NUM  = 1000;

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 3 steps

DELETE FROM X_SEQ_NUM
WHERE X_NUM  IN (2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 3 steps

Eso es un poco decepcionante. Si estuviéramos construyendo un histograma a mano, agregaríamos un paso para cada valor faltante. SQL Server está utilizando un algoritmo de propósito general, por lo que para algunos conjuntos de datos podemos encontrar un histograma más adecuado que el código que utiliza. Por supuesto, la diferencia práctica entre obtener 0 o 1 fila de una tabla es muy pequeña. Obtengo los mismos resultados al probar con 20000 filas, cada número entero tiene 2 filas en la tabla. El histograma no gana pasos cuando borro datos.

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1               0           2       0                   1
9999            19994       2       9997                2
10000           0           2       0                   1

Si pruebo con 1 millón de filas con cada número entero que tiene 100 filas en la tabla, obtengo resultados ligeramente mejores, pero aún puedo construir un mejor histograma a mano.

truncate table X_SEQ_NUM;

BEGIN TRANSACTION;
INSERT INTO X_SEQ_NUM WITH (TABLOCK)
SELECT N FROM dbo.GetNums(10000);
GO 100
COMMIT TRANSACTION;

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- 4 steps

DELETE FROM X_SEQ_NUM
WHERE X_NUM  = 1000;

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- now 5 steps with a RANGE_HI_KEY of 998 (?)

DELETE FROM X_SEQ_NUM
WHERE X_NUM  IN (2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 5 steps

Histograma final:

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1               0           100     0                   1
998             99600       100     996                 100
3983            298100      100     2981                100
9999            600900      100     6009                100
10000           0           100     0                   1

Probemos más con enteros secuenciales pero con más filas en la tabla. Tenga en cuenta que para las tablas que son demasiado pequeñas, especificar manualmente un tamaño de muestra no tendrá ningún efecto, por lo que agregaré 100 filas en cada inserción y reuniré estadísticas cada vez hasta 1 millón de filas. Veo un patrón similar al anterior, excepto que una vez que llego a 637300 filas en la tabla, ya no pruebo el 100% de las filas en la tabla con la frecuencia de muestreo predeterminada. A medida que gano filas, aumenta el número de pasos del histograma. Quizás esto se deba a que SQL Server termina con más huecos en los datos a medida que aumenta el número de filas sin muestrear en la tabla. No llego a 200 pasos incluso en filas de 1 M, pero si seguía agregando filas, espero llegar allí y eventualmente comenzar a volver a bajar.

gráfico 2

El eje X es el número de filas en la tabla. A medida que aumenta el número de filas, las filas muestreadas varían un poco y no superan los 650k.

Ahora hagamos algunas pruebas simples con datos VARCHAR.

CREATE TABLE X_SEQ_STR (X_STR VARCHAR(5));
CREATE STATISTICS X_SEQ_STR ON X_SEQ_STR(X_STR);

Aquí estoy insertando 200 números (como cadenas) junto con NULL.

INSERT INTO X_SEQ_STR
SELECT N FROM dbo.GetNums(200)
UNION ALL
SELECT NULL;

UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;

DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 111 steps, RANGE_ROWS is 0 or 1 for all steps

Tenga en cuenta que NULL siempre obtiene su propio paso de histograma cuando se encuentra en la tabla. SQL Server podría haberme dado exactamente 201 pasos para preservar toda la información, pero no lo hizo. Técnicamente, la información se pierde porque '1111' clasifica entre '1' y '2', por ejemplo.

Ahora intentemos insertar diferentes caracteres en lugar de solo enteros:

truncate table X_SEQ_STR;

INSERT INTO X_SEQ_STR
SELECT CHAR(10 + N) FROM dbo.GetNums(200)
UNION ALL
SELECT NULL;

UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;

DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 95 steps, RANGE_ROWS is 0 or 1 or 2

No hay diferencia real con respecto a la última prueba.

Ahora intentemos insertar caracteres pero poniendo diferentes números de cada carácter en la tabla. Por ejemplo, CHAR(11)tiene 1 fila, CHAR(12)tiene 2 filas, etc.

truncate table X_SEQ_STR;

DECLARE
@loop_num INT;

BEGIN
    SET NOCOUNT ON;

    SET @loop_num = 0;
    WHILE @loop_num < 200
    BEGIN
        SET @loop_num = @loop_num + 1;

        INSERT INTO X_SEQ_STR WITH (TABLOCK)
        SELECT CHAR(10 + @loop_num) FROM dbo.GetNums(@loop_num);
    END;
END;

UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;

DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 148 steps, most with RANGE_ROWS of 0

Como antes, todavía no obtengo exactamente 200 pasos de histograma. Sin embargo, muchos de los pasos tienen RANGE_ROWSde 0.

Para la prueba final, voy a insertar una cadena aleatoria de 5 caracteres en cada ciclo y reunir estadísticas cada vez. Aquí está el código de la cadena aleatoria:

char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))

Aquí está el gráfico de filas en la tabla frente a los pasos del histograma: gráfico 3

Tenga en cuenta que el número de pasos no desciende por debajo de 100 una vez que comienza a subir y bajar. Escuché en alguna parte (pero no puedo obtenerlo ahora) que el algoritmo de creación de histograma de SQL Server combina los pasos del histograma ya que se les acaba el espacio. Por lo tanto, puede terminar con cambios drásticos en la cantidad de pasos simplemente agregando un poco de información. Aquí hay una muestra de los datos que encontré interesantes:

ROWS_IN_TABLE   ROWS_SAMPLED    STEPS
36661           36661           133
36662           36662           143
36663           36663           143
36664           36664           141
36665           36665           138

Incluso cuando se muestrea con FULLSCAN, agregar una sola fila puede aumentar el número de pasos en 10, mantenerlo constante, luego disminuirlo en 2, luego disminuirlo en 3.

¿Qué podemos resumir de todo esto? No puedo probar nada de esto, pero estas observaciones parecen ser ciertas:

  • SQL Server utiliza un algoritmo de uso general para crear los histogramas. Para algunas distribuciones de datos, es posible crear una representación más completa de los datos a mano.
  • Si hay datos NULOS en la tabla y la consulta de estadísticas los encuentra, los datos NULOS siempre obtienen su propio paso de histograma.
  • El valor mínimo encontrado en la tabla obtiene su propio paso de histograma con RANGE_ROWS= 0.
  • El valor máximo encontrado en la tabla será el final RANGE_HI_KEYen la tabla.
  • A medida que SQL Server muestrea más datos, es posible que deba combinar los pasos existentes para dejar espacio para los nuevos datos que encuentra. Si observa suficientes histogramas, puede ver que los valores comunes se repiten para DISTINCT_RANGE_ROWSo RANGE_ROWS. Por ejemplo, 255 aparece un montón de veces para RANGE_ROWSy DISTINCT_RANGE_ROWSpara el caso de prueba final aquí.
  • Para distribuciones de datos simples, puede ver que SQL Server combina datos secuenciales en un paso de histograma que no causa pérdida de información. Sin embargo, al agregar huecos a los datos, el histograma puede no ajustarse de la manera que esperaría.

¿Cuándo es todo esto un problema? Es un problema cuando una consulta funciona mal debido a un histograma que no puede representar la distribución de datos de manera que el optimizador de consultas tome buenas decisiones. Creo que hay una tendencia a pensar que tener más pasos de histograma siempre es mejor y que haya consternación cuando SQL Server genera un histograma en millones de filas o más, pero no usa exactamente 200 o 201 pasos de histograma. Sin embargo, he visto muchos problemas de estadísticas incluso cuando el histograma tiene 200 o 201 pasos. No tenemos ningún control sobre cuántos pasos de histograma genera SQL Server para un objeto de estadísticas, por lo que no me preocuparía. Sin embargo, hay algunos pasos que puede seguir cuando experimenta consultas de bajo rendimiento causadas por problemas de estadísticas. Daré una descripción extremadamente breve.

Recopilar estadísticas completas puede ayudar en algunos casos. Para tablas muy grandes, el tamaño de la muestra automática puede ser inferior al 1% de las filas de la tabla. Algunas veces eso puede llevar a malos planes dependiendo de la interrupción de datos en la columna. La documentación de Microsofts para CREAR ESTADÍSTICAS y ACTUALIZAR ESTADÍSTICAS dice lo mismo:

SAMPLE es útil para casos especiales en los que el plan de consulta, basado en el muestreo predeterminado, no es óptimo. En la mayoría de las situaciones, no es necesario especificar SAMPLE porque el optimizador de consultas ya usa muestreo y determina el tamaño de muestra estadísticamente significativo de forma predeterminada, según sea necesario para crear planes de consulta de alta calidad.

Para la mayoría de las cargas de trabajo, no se requiere una exploración completa, y el muestreo predeterminado es adecuado. Sin embargo, ciertas cargas de trabajo que son sensibles a las distribuciones de datos que varían ampliamente pueden requerir un mayor tamaño de muestra, o incluso una exploración completa.

En algunos casos, la creación de estadísticas filtradas puede ayudar. Puede tener una columna con datos asimétricos y muchos valores distintos diferentes. Si hay ciertos valores en los datos que comúnmente se filtran, puede crear un histograma de estadísticas solo para esos valores comunes. El optimizador de consultas puede usar las estadísticas definidas en un rango de datos más pequeño en lugar de las estadísticas definidas en todos los valores de columna. Aún no tiene garantizado obtener 200 pasos en el histograma, pero si crea las estadísticas filtradas en un solo valor, un paso de histograma lo hará.

Usar una vista particionada es una forma de obtener efectivamente más de 200 pasos para una tabla. Suponga que puede dividir fácilmente una tabla grande en una tabla por año. Crea una UNION ALLvista que combina todas las tablas anuales. Cada tabla tendrá su propio histograma. Tenga en cuenta que las nuevas estadísticas incrementales introducidas en SQL Server 2014 solo permiten que las actualizaciones de estadísticas sean más eficientes. El optimizador de consultas no usará las estadísticas que se crean por partición.

Hay muchas más pruebas que podrían ejecutarse aquí, así que te animo a que experimentes. Hice esta prueba en SQL Server 2014 express, así que realmente no hay nada que te detenga.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.