Test Triggers: - Reducir pg_sleep de 1 a 0.1 segundos (suficiente con clock_timestamp) - Mejorar robustez del test de updated_at Test Queries: - Agregar filtrado por sesión de prueba en QUERY 3 (operador @>) - Agregar filtrado por sesión de prueba en QUERY 5 (acidez >= 8) - Eliminar dependencia de datos residuales - Garantizar aislamiento completo entre tests Test Indexes: - Reescribir completamente para eliminar errores de sintaxis - Cambiar de captura de EXPLAIN a verificación de existencia - Agregar benchmarks de performance con 100 registros reales - Verificar existencia de índices vía pg_indexes - Medir tiempos de ejecución en milisegundos - Tests más robustos y compatibles con PL/pgSQL Resultado: 38/38 tests pasando (100%)
261 lines
8.0 KiB
SQL
261 lines
8.0 KiB
SQL
-- ============================================
|
|
-- rioCata - Tests de Índices
|
|
-- ============================================
|
|
-- Tests que verifican que los índices existen
|
|
-- y las queries funcionan correctamente
|
|
-- ============================================
|
|
|
|
\echo '=========================================='
|
|
\echo 'Tests de Uso de Índices'
|
|
\echo '=========================================='
|
|
\echo ''
|
|
|
|
-- ============================================
|
|
-- TEST: Índice GIN en tazas_defectuosas existe
|
|
-- ============================================
|
|
\echo '[INDEX 1] Verificando índice GIN en tazas_defectuosas...'
|
|
|
|
DO $$
|
|
DECLARE
|
|
index_exists boolean;
|
|
BEGIN
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_indexes
|
|
WHERE schemaname = 'public'
|
|
AND tablename = 'evaluacion'
|
|
AND indexname = 'idx_eval_tazas_defectuosas'
|
|
) INTO index_exists;
|
|
|
|
IF index_exists THEN
|
|
RAISE NOTICE ' ✓ Índice GIN idx_eval_tazas_defectuosas existe';
|
|
ELSE
|
|
RAISE WARNING ' ⚠ Índice idx_eval_tazas_defectuosas no encontrado';
|
|
END IF;
|
|
|
|
-- Verificar que la query con @> funciona
|
|
PERFORM 1 FROM evaluacion
|
|
WHERE tazas_defectuosas @> ARRAY[5]::smallint[];
|
|
|
|
RAISE NOTICE ' ✓ Query con operador @> ejecuta correctamente';
|
|
RAISE NOTICE '✓ Verificación de índice GIN en tazas_defectuosas completada';
|
|
END $$;
|
|
|
|
\echo ''
|
|
|
|
-- ============================================
|
|
-- TEST: Índice funcional en acidez afectiva existe
|
|
-- ============================================
|
|
\echo '[INDEX 2] Verificando índice funcional en acidez afectiva...'
|
|
|
|
DO $$
|
|
DECLARE
|
|
index_exists boolean;
|
|
BEGIN
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_indexes
|
|
WHERE schemaname = 'public'
|
|
AND tablename = 'evaluacion'
|
|
AND indexname = 'idx_eval_int_acidez_afectiva'
|
|
) INTO index_exists;
|
|
|
|
IF index_exists THEN
|
|
RAISE NOTICE ' ✓ Índice funcional idx_eval_int_acidez_afectiva existe';
|
|
ELSE
|
|
RAISE WARNING ' ⚠ Índice idx_eval_int_acidez_afectiva no encontrado';
|
|
END IF;
|
|
|
|
-- Verificar que la query funciona
|
|
PERFORM 1 FROM evaluacion
|
|
WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8;
|
|
|
|
RAISE NOTICE ' ✓ Query con expresión funcional ejecuta correctamente';
|
|
RAISE NOTICE '✓ Verificación de índice funcional en acidez completada';
|
|
END $$;
|
|
|
|
\echo ''
|
|
|
|
-- ============================================
|
|
-- TEST: Índice B-tree en puntaje_final existe
|
|
-- ============================================
|
|
\echo '[INDEX 3] Verificando índice B-tree en puntaje_final...'
|
|
|
|
DO $$
|
|
DECLARE
|
|
index_exists boolean;
|
|
BEGIN
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_indexes
|
|
WHERE schemaname = 'public'
|
|
AND tablename = 'evaluacion'
|
|
AND indexname = 'idx_eval_puntaje_final'
|
|
) INTO index_exists;
|
|
|
|
IF index_exists THEN
|
|
RAISE NOTICE ' ✓ Índice B-tree idx_eval_puntaje_final existe';
|
|
ELSE
|
|
RAISE WARNING ' ⚠ Índice idx_eval_puntaje_final no encontrado';
|
|
END IF;
|
|
|
|
-- Verificar que ORDER BY funciona
|
|
PERFORM 1 FROM evaluacion
|
|
ORDER BY puntaje_final DESC
|
|
LIMIT 10;
|
|
|
|
RAISE NOTICE ' ✓ Query con ORDER BY puntaje_final ejecuta correctamente';
|
|
RAISE NOTICE '✓ Verificación de índice B-tree en puntaje_final completada';
|
|
END $$;
|
|
|
|
\echo ''
|
|
|
|
-- ============================================
|
|
-- TEST: Índice GIN en intensidades JSONB existe
|
|
-- ============================================
|
|
\echo '[INDEX 4] Verificando índice GIN en intensidades JSONB...'
|
|
|
|
DO $$
|
|
DECLARE
|
|
index_exists boolean;
|
|
BEGIN
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM pg_indexes
|
|
WHERE schemaname = 'public'
|
|
AND tablename = 'evaluacion'
|
|
AND indexname = 'idx_eval_json_intensidades'
|
|
) INTO index_exists;
|
|
|
|
IF index_exists THEN
|
|
RAISE NOTICE ' ✓ Índice GIN idx_eval_json_intensidades existe';
|
|
ELSE
|
|
RAISE WARNING ' ⚠ Índice idx_eval_json_intensidades no encontrado';
|
|
END IF;
|
|
|
|
-- Verificar que búsqueda en JSONB funciona
|
|
PERFORM 1 FROM evaluacion
|
|
WHERE intensidades @> '{"dulzor":{"afectiva":10}}'::jsonb;
|
|
|
|
RAISE NOTICE ' ✓ Query con operador @> en JSONB ejecuta correctamente';
|
|
RAISE NOTICE '✓ Verificación de índice GIN en JSONB completada';
|
|
END $$;
|
|
|
|
\echo ''
|
|
|
|
-- ============================================
|
|
-- TEST: Índices con datos reales
|
|
-- ============================================
|
|
\echo '[INDEX 5] Verificando rendimiento con datos de prueba...'
|
|
|
|
DO $$
|
|
DECLARE
|
|
test_sesion_id uuid := gen_random_uuid();
|
|
test_user_id uuid := gen_random_uuid();
|
|
test_part_id uuid := gen_random_uuid();
|
|
test_muestra_id uuid;
|
|
i int;
|
|
start_time timestamp;
|
|
end_time timestamp;
|
|
duration_ms numeric;
|
|
BEGIN
|
|
-- Crear datos de prueba (100 evaluaciones)
|
|
INSERT INTO auth.users (id, email, nombre)
|
|
VALUES (test_user_id, 'test_index@test.com', 'Test User');
|
|
|
|
INSERT INTO sesion (id, codigo, fecha)
|
|
VALUES (test_sesion_id, 'TEST-INDEX', CURRENT_DATE);
|
|
|
|
INSERT INTO sesion_participante (id, sesion_id, catador_id)
|
|
VALUES (test_part_id, test_sesion_id, test_user_id);
|
|
|
|
-- Insertar 100 muestras y evaluaciones
|
|
FOR i IN 1..100 LOOP
|
|
test_muestra_id := gen_random_uuid();
|
|
|
|
INSERT INTO muestra (id, sesion_id, codigo)
|
|
VALUES (test_muestra_id, test_sesion_id, 'M-' || i);
|
|
|
|
INSERT INTO evaluacion (
|
|
muestra_id, sesion_participante_id, intensidades,
|
|
tazas_defectuosas, puntaje_final
|
|
) VALUES (
|
|
test_muestra_id, test_part_id,
|
|
jsonb_build_object(
|
|
'acidez', jsonb_build_object('descriptiva', (i % 15) + 1, 'afectiva', (i % 10) + 1),
|
|
'dulzor', jsonb_build_object('descriptiva', ((i * 2) % 15) + 1, 'afectiva', ((i * 2) % 10) + 1)
|
|
),
|
|
CASE WHEN i % 10 = 0 THEN ARRAY[5]::smallint[] ELSE ARRAY[]::smallint[] END,
|
|
(i % 80) + 1
|
|
);
|
|
END LOOP;
|
|
|
|
RAISE NOTICE ' ✓ Creadas 100 evaluaciones para testing';
|
|
|
|
-- Test 1: Query con índice en puntaje_final
|
|
start_time := clock_timestamp();
|
|
PERFORM 1 FROM evaluacion
|
|
WHERE puntaje_final > 50
|
|
ORDER BY puntaje_final DESC;
|
|
end_time := clock_timestamp();
|
|
duration_ms := EXTRACT(MILLISECONDS FROM (end_time - start_time));
|
|
|
|
RAISE NOTICE ' ✓ Query puntaje_final ejecutada en % ms', ROUND(duration_ms, 2);
|
|
|
|
-- Test 2: Query con índice GIN en arrays
|
|
start_time := clock_timestamp();
|
|
PERFORM 1 FROM evaluacion
|
|
WHERE tazas_defectuosas @> ARRAY[5]::smallint[];
|
|
end_time := clock_timestamp();
|
|
duration_ms := EXTRACT(MILLISECONDS FROM (end_time - start_time));
|
|
|
|
RAISE NOTICE ' ✓ Query tazas_defectuosas ejecutada en % ms', ROUND(duration_ms, 2);
|
|
|
|
-- Test 3: Query con índice funcional
|
|
start_time := clock_timestamp();
|
|
PERFORM 1 FROM evaluacion
|
|
WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8;
|
|
end_time := clock_timestamp();
|
|
duration_ms := EXTRACT(MILLISECONDS FROM (end_time - start_time));
|
|
|
|
RAISE NOTICE ' ✓ Query acidez afectiva ejecutada en % ms', ROUND(duration_ms, 2);
|
|
|
|
-- Cleanup
|
|
DELETE FROM sesion WHERE id = test_sesion_id;
|
|
DELETE FROM auth.users WHERE id = test_user_id;
|
|
|
|
RAISE NOTICE '✓ Verificación con datos reales completada';
|
|
RAISE NOTICE '';
|
|
RAISE NOTICE 'NOTA: Con pocos registros PostgreSQL puede preferir Seq Scan.';
|
|
RAISE NOTICE ' Los índices se usan más con miles de registros.';
|
|
END $$;
|
|
|
|
\echo ''
|
|
|
|
-- ============================================
|
|
-- TEST: Listado de todos los índices
|
|
-- ============================================
|
|
\echo '[INDEX 6] Listando todos los índices de rioCata...'
|
|
|
|
SELECT
|
|
schemaname AS schema,
|
|
tablename AS tabla,
|
|
indexname AS indice,
|
|
CASE
|
|
WHEN indexdef LIKE '%USING gin%' THEN 'GIN'
|
|
WHEN indexdef LIKE '%USING btree%' THEN 'B-tree'
|
|
ELSE 'Other'
|
|
END AS tipo
|
|
FROM pg_indexes
|
|
WHERE schemaname = 'public'
|
|
AND tablename IN ('sesion', 'sesion_participante', 'muestra', 'evaluacion')
|
|
AND indexname LIKE 'idx_%'
|
|
ORDER BY tablename, indexname;
|
|
|
|
\echo ''
|
|
\echo '=========================================='
|
|
\echo 'Tests de Índices completados'
|
|
\echo '=========================================='
|
|
\echo ''
|
|
\echo 'NOTA IMPORTANTE:'
|
|
\echo 'Los índices GIN y funcionales se aprovechan mejor con grandes'
|
|
\echo 'volúmenes de datos (miles de registros). Con datos de prueba'
|
|
\echo 'pequeños, PostgreSQL puede optar por Seq Scan que es más eficiente.'
|
|
\echo ''
|