El índice SQL permite encontrar rápidamente una cadena que coincida con mi consulta. Ahora, tengo que buscar en una tabla grande las cadenas que hacen no coincide con. Por supuesto, el índice normal no ayudará y tengo que hacer una exploración secuencial lenta:Índices SQL para búsquedas "no iguales"
essais=> \d phone_idx
Index "public.phone_idx"
Column | Type
--------+------
phone | text
btree, for table "public.phonespersons"
essais=> EXPLAIN SELECT person FROM PhonesPersons WHERE phone = '+33 1234567';
QUERY PLAN
-------------------------------------------------------------------------------
Index Scan using phone_idx on phonespersons (cost=0.00..8.41 rows=1 width=4)
Index Cond: (phone = '+33 1234567'::text)
(2 rows)
essais=> EXPLAIN SELECT person FROM PhonesPersons WHERE phone != '+33 1234567';
QUERY PLAN
----------------------------------------------------------------------
Seq Scan on phonespersons (cost=0.00..18621.00 rows=999999 width=4)
Filter: (phone <> '+33 1234567'::text)
(2 rows)
entiendo (ver explicaciones muy buenas Marcos Byers') que PostgreSQL puede decidir no utilizar un índice cuando se ve que un escaneo secuencial sería más rápido (por ejemplo, si casi todas las tuplas coinciden). Pero, aquí, las búsquedas "no iguales" son realmente más lentas.
¿Alguna manera de hacer que estas búsquedas "no sean iguales" más rápido?
Aquí hay otro ejemplo, para abordar las excelentes observaciones de Mark Byers. El índice se utiliza para la consulta '=' (que devuelve la gran mayoría de tuplas), pero no para la consulta '=':
essais=> \d tld_idx
Index "public.tld_idx"
Column | Type
-----------------+------
pg_expression_1 | text
btree, for table "public.emailspersons"
essais=> EXPLAIN ANALYZE SELECT person FROM EmailsPersons WHERE tld(email) = 'fr';
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tld_idx on emailspersons (cost=0.25..4010.79 rows=97033 width=4) (actual time=0.137..261.123 rows=97110 loops=1)
Index Cond: (tld(email) = 'fr'::text)
Total runtime: 444.800 ms
(3 rows)
essais=> EXPLAIN ANALYZE SELECT person FROM EmailsPersons WHERE tld(email) != 'fr';
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
Seq Scan on emailspersons (cost=0.00..27129.00 rows=2967 width=4) (actual time=1.004..1031.224 rows=2890 loops=1)
Filter: (tld(email) <> 'fr'::text)
Total runtime: 1037.278 ms
(3 rows)
DBMS es PostgreSQL 8.3 (pero puede actualizar a 8.4) .
Acabo de probar su idea de volver a escribir "<>" a "< OR >" y funciona. EXPLAIN muestra que el índice se usa y el rendimiento mejora mucho. Hago más pruebas y aceptaré tu respuesta. Pregunta: ¿por qué PostgreSQL no puede hacer esto reescribiéndose? – bortzmeyer
@bortzmeyer Posiblemente porque el sistema del operador es tan general, necesitaría alguna forma de relacionar el par de operadores "="/"<>" con "<" and ">". Puede valer la pena sugerir a la lista postgresql como una característica. – araqnid
OK, funciona bien, gracias. Una pequeña advertencia: no todos los índices de PostgreSQL tienen orden http://www.postgresql.org/docs/current/interactive/indexes-types.html – bortzmeyer