seguito @Justin Cave di risposta, ecco un piccolo test case per dimostrare che Oracle farebbe una INDEX RANGE SCAN seguito da un INERITORE ITERATORE consultato filtro predicato:
WHERE (key_part_1, key_part_2) IN (('B',1), ('C',2))
Setup
SQL> CREATE TABLE t(key1 VARCHAR2(1), key2 NUMBER);
Table created.
SQL>
SQL> INSERT INTO t VALUES('A', 1);
1 row created.
SQL> INSERT INTO t VALUES('B', 1);
1 row created.
SQL> INSERT INTO t VALUES('C', 2);
1 row created.
SQL> INSERT INTO t VALUES('C', 3);
1 row created.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
Un indice composito su key1 e key2:
SQL> CREATE INDEX t_idx ON t(key1, key2);
Index created.
SQL>
Raccogliere statistiche:
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 'T');
PL/SQL procedure successfully completed.
SQL>
eseguire la query:
SQL> SELECT * FROM t
2 WHERE (key1, key2) IN (('B',1), ('C',2));
K KEY2
- ----------
B 1
C 2
SQL>
Quindi, dà l'output corretto.
Vediamo il spiegano piano di:
Caso # 1 coppia di valori-chiave nello stesso ordine dell'indice. Chiave principale in testa.
SQL> SELECT * FROM TABLE(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2301620486
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 10 | 1 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
|* 2 | INDEX RANGE SCAN| T_IDX | 2 | 10 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------
2 - access(("KEY1"='B' AND "KEY2"=1 OR "KEY1"='C' AND "KEY2"=2))
14 rows selected.
Caso # 2 coppia chiave-valore in ordine inverso dell'indice. Chiave principale al contrario.
SQL> EXPLAIN PLAN FOR SELECT * FROM t
2 WHERE (key2, key1) IN ((1, 'B'), (2, 'C'));
Explained.
SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2301620486
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 10 | 1 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
|* 2 | INDEX RANGE SCAN| T_IDX | 2 | 10 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------
2 - access(("KEY1"='B' AND "KEY2"=1 OR "KEY1"='C' AND "KEY2"=2))
14 rows selected.
In entrambi i casi, Oracle utilizza l'indice.
Non so se Oracle ha lo stesso problema, ma in MySQL se si utilizza questa sintassi non verrà utilizzato l'indice. – Barmar
Funziona bene anche in Postgres. –