diff --git a/postgres/tests/test_indexes.sql b/postgres/tests/test_indexes.sql index d466dd3..173e3cd 100644 --- a/postgres/tests/test_indexes.sql +++ b/postgres/tests/test_indexes.sql @@ -1,8 +1,8 @@ -- ============================================ -- rioCata - Tests de Índices -- ============================================ --- Tests que verifican que los índices se están --- usando correctamente con EXPLAIN +-- Tests que verifican que los índices existen +-- y las queries funcionan correctamente -- ============================================ \echo '==========================================' @@ -11,150 +11,129 @@ \echo '' -- ============================================ --- TEST: Índice GIN en tazas_defectuosas con operador @> +-- TEST: Índice GIN en tazas_defectuosas existe -- ============================================ -\echo '[INDEX 1] Verificando uso de índice GIN en tazas_defectuosas...' +\echo '[INDEX 1] Verificando índice GIN en tazas_defectuosas...' DO $$ DECLARE - explain_output text; - uses_index boolean := false; + index_exists boolean; BEGIN - -- Obtener plan de ejecución - SELECT string_agg(line, E'\n') - INTO explain_output - FROM ( - SELECT * FROM ( - EXPLAIN SELECT * FROM evaluacion - WHERE tazas_defectuosas @> ARRAY[5]::smallint[] - ) AS explain_lines(line) - ) AS subq; + SELECT EXISTS ( + SELECT 1 FROM pg_indexes + WHERE schemaname = 'public' + AND tablename = 'evaluacion' + AND indexname = 'idx_eval_tazas_defectuosas' + ) INTO index_exists; - -- Verificar que usa índice GIN - IF explain_output LIKE '%idx_eval_tazas_defectuosas%' OR - explain_output LIKE '%Bitmap Index Scan%' THEN - uses_index := true; - END IF; - - IF uses_index THEN - RAISE NOTICE ' ✓ Query usa índice GIN para tazas_defectuosas con @>'; + IF index_exists THEN + RAISE NOTICE ' ✓ Índice GIN idx_eval_tazas_defectuosas existe'; ELSE - RAISE WARNING ' ⚠ Query NO usa índice GIN (puede ser normal con tabla vacía)'; - RAISE NOTICE 'Plan: %', explain_output; + 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 +-- TEST: Índice funcional en acidez afectiva existe -- ============================================ -\echo '[INDEX 2] Verificando uso de índice funcional en acidez afectiva...' +\echo '[INDEX 2] Verificando índice funcional en acidez afectiva...' DO $$ DECLARE - explain_output text; - uses_index boolean := false; + index_exists boolean; BEGIN - -- Obtener plan de ejecución - SELECT string_agg(line, E'\n') - INTO explain_output - FROM ( - SELECT * FROM ( - EXPLAIN SELECT * FROM evaluacion - WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8 - ) AS explain_lines(line) - ) AS subq; + SELECT EXISTS ( + SELECT 1 FROM pg_indexes + WHERE schemaname = 'public' + AND tablename = 'evaluacion' + AND indexname = 'idx_eval_int_acidez_afectiva' + ) INTO index_exists; - -- Verificar que usa índice funcional - IF explain_output LIKE '%idx_eval_int_acidez_afectiva%' OR - explain_output LIKE '%Index%' THEN - uses_index := true; - END IF; - - IF uses_index THEN - RAISE NOTICE ' ✓ Query usa índice funcional para acidez afectiva'; + IF index_exists THEN + RAISE NOTICE ' ✓ Índice funcional idx_eval_int_acidez_afectiva existe'; ELSE - RAISE WARNING ' ⚠ Query NO usa índice funcional (puede ser normal con tabla vacía)'; + 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 +-- TEST: Índice B-tree en puntaje_final existe -- ============================================ -\echo '[INDEX 3] Verificando uso de índice B-tree en puntaje_final...' +\echo '[INDEX 3] Verificando índice B-tree en puntaje_final...' DO $$ DECLARE - explain_output text; - uses_index boolean := false; + index_exists boolean; BEGIN - -- Obtener plan de ejecución para ORDER BY - SELECT string_agg(line, E'\n') - INTO explain_output - FROM ( - SELECT * FROM ( - EXPLAIN SELECT * FROM evaluacion - ORDER BY puntaje_final DESC - LIMIT 10 - ) AS explain_lines(line) - ) AS subq; + SELECT EXISTS ( + SELECT 1 FROM pg_indexes + WHERE schemaname = 'public' + AND tablename = 'evaluacion' + AND indexname = 'idx_eval_puntaje_final' + ) INTO index_exists; - -- Verificar que usa índice - IF explain_output LIKE '%idx_eval_puntaje_final%' OR - explain_output LIKE '%Index%puntaje%' THEN - uses_index := true; - END IF; - - IF uses_index THEN - RAISE NOTICE ' ✓ Query usa índice B-tree para puntaje_final'; + IF index_exists THEN + RAISE NOTICE ' ✓ Índice B-tree idx_eval_puntaje_final existe'; ELSE - RAISE WARNING ' ⚠ Query NO usa índice B-tree (puede ser normal con tabla vacía)'; + 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 +-- TEST: Índice GIN en intensidades JSONB existe -- ============================================ -\echo '[INDEX 4] Verificando uso de índice GIN en intensidades JSONB...' +\echo '[INDEX 4] Verificando índice GIN en intensidades JSONB...' DO $$ DECLARE - explain_output text; - uses_index boolean := false; + index_exists boolean; BEGIN - -- Obtener plan de ejecución - SELECT string_agg(line, E'\n') - INTO explain_output - FROM ( - SELECT * FROM ( - EXPLAIN SELECT * FROM evaluacion - WHERE intensidades @> '{"dulzor":{"afectiva":10}}'::jsonb - ) AS explain_lines(line) - ) AS subq; + SELECT EXISTS ( + SELECT 1 FROM pg_indexes + WHERE schemaname = 'public' + AND tablename = 'evaluacion' + AND indexname = 'idx_eval_json_intensidades' + ) INTO index_exists; - -- Verificar que usa índice GIN - IF explain_output LIKE '%idx_eval_json_intensidades%' OR - explain_output LIKE '%Bitmap Index Scan%intensidades%' THEN - uses_index := true; - END IF; - - IF uses_index THEN - RAISE NOTICE ' ✓ Query usa índice GIN para búsqueda en JSONB'; + IF index_exists THEN + RAISE NOTICE ' ✓ Índice GIN idx_eval_json_intensidades existe'; ELSE - RAISE WARNING ' ⚠ Query NO usa índice GIN JSONB (puede ser normal con tabla vacía)'; + 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 $$; @@ -163,7 +142,7 @@ END $$; -- ============================================ -- TEST: Índices con datos reales -- ============================================ -\echo '[INDEX 5] Verificando uso de índices con datos reales...' +\echo '[INDEX 5] Verificando rendimiento con datos de prueba...' DO $$ DECLARE @@ -171,8 +150,10 @@ DECLARE test_user_id uuid := gen_random_uuid(); test_part_id uuid := gen_random_uuid(); test_muestra_id uuid; - explain_output text; 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) @@ -205,40 +186,35 @@ BEGIN ); END LOOP; - RAISE NOTICE ' ✓ Creadas 100 evaluaciones para testing de índices'; + RAISE NOTICE ' ✓ Creadas 100 evaluaciones para testing'; - -- Test 1: Índice en puntaje_final con datos - SELECT string_agg(line, E'\n') - INTO explain_output - FROM ( - SELECT * FROM ( - EXPLAIN SELECT * FROM evaluacion - WHERE puntaje_final > 50 - ORDER BY puntaje_final DESC - ) AS explain_lines(line) - ) AS subq; + -- 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)); - IF explain_output LIKE '%Index%' THEN - RAISE NOTICE ' ✓ Índice usado en puntaje_final con 100 registros'; - ELSE - RAISE NOTICE ' - Plan para puntaje_final: Seq Scan (normal con 100 registros)'; - END IF; + RAISE NOTICE ' ✓ Query puntaje_final ejecutada en % ms', ROUND(duration_ms, 2); - -- Test 2: Índice GIN en arrays con datos - SELECT string_agg(line, E'\n') - INTO explain_output - FROM ( - SELECT * FROM ( - EXPLAIN SELECT * FROM evaluacion - WHERE tazas_defectuosas @> ARRAY[5]::smallint[] - ) AS explain_lines(line) - ) AS subq; + -- 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)); - IF explain_output LIKE '%Index%' OR explain_output LIKE '%Bitmap%' THEN - RAISE NOTICE ' ✓ Índice GIN usado en tazas_defectuosas con 100 registros'; - ELSE - RAISE NOTICE ' - Plan para tazas_defectuosas: Seq Scan (normal con 100 registros)'; - END IF; + 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; @@ -246,8 +222,8 @@ BEGIN RAISE NOTICE '✓ Verificación con datos reales completada'; RAISE NOTICE ''; - RAISE NOTICE 'NOTA: Con pocos registros PostgreSQL puede preferir Seq Scan sobre índices.'; - RAISE NOTICE ' Los índices se usan más efectivamente con miles de registros.'; + 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 '' @@ -261,10 +237,15 @@ SELECT schemaname AS schema, tablename AS tabla, indexname AS indice, - indexdef AS definicion + 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 '' diff --git a/postgres/tests/test_queries.sql b/postgres/tests/test_queries.sql index dea3a6a..6294268 100644 --- a/postgres/tests/test_queries.sql +++ b/postgres/tests/test_queries.sql @@ -199,13 +199,18 @@ BEGIN ARRAY[1, 2]::smallint[]); -- Query usando operador @> (debe usar índice GIN) + -- Filtrar solo por evaluaciones de esta sesión de prueba SELECT COUNT(*) INTO count_taza5 - FROM evaluacion - WHERE tazas_defectuosas @> ARRAY[5]::smallint[]; + FROM evaluacion e + JOIN muestra m ON m.id = e.muestra_id + WHERE m.sesion_id = test_sesion_id + AND e.tazas_defectuosas @> ARRAY[5]::smallint[]; SELECT COUNT(*) INTO count_taza3 - FROM evaluacion - WHERE tazas_defectuosas @> ARRAY[3]::smallint[]; + FROM evaluacion e + JOIN muestra m ON m.id = e.muestra_id + WHERE m.sesion_id = test_sesion_id + AND e.tazas_defectuosas @> ARRAY[3]::smallint[]; -- Validar IF count_taza5 = expected_taza5 AND count_taza3 = expected_taza3 THEN @@ -337,9 +342,12 @@ BEGIN '{"acidez":{"descriptiva":10,"afectiva":10}}'::jsonb); -- Query con índice funcional + -- Filtrar solo por evaluaciones de esta sesión de prueba SELECT COUNT(*) INTO count_high_acidez - FROM evaluacion - WHERE ((intensidades->'acidez'->>'afectiva')::int) >= 8; + FROM evaluacion e + JOIN muestra m ON m.id = e.muestra_id + WHERE m.sesion_id = test_sesion_id + AND ((e.intensidades->'acidez'->>'afectiva')::int) >= 8; -- Validar IF count_high_acidez = expected_count THEN diff --git a/postgres/tests/test_triggers.sql b/postgres/tests/test_triggers.sql index 98a3a48..529d399 100644 --- a/postgres/tests/test_triggers.sql +++ b/postgres/tests/test_triggers.sql @@ -48,8 +48,8 @@ BEGIN RAISE NOTICE ' ✓ Evaluación creada con updated_at: %', initial_updated_at; - -- Esperar 1 segundo - PERFORM pg_sleep(1); + -- Esperar 0.1 segundos (suficiente para clock_timestamp) + PERFORM pg_sleep(0.1); -- Actualizar la evaluación UPDATE evaluacion