Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle Select * renvoie des lignes mais Select count(1) renvoie 0

Des résultats erronés peuvent être causés par des corruptions, des bogues et des fonctionnalités qui modifient silencieusement les instructions SQL.

  1. Indice corrompu. Très rarement, un index est corrompu et les données d'un index ne correspondent pas aux données d'une table. Cela provoque des résultats inattendus lorsque le plan de requête change et qu'un index est utilisé, mais tout semble normal pour différentes requêtes qui utilisent l'accès à la table. Parfois, la simple reconstruction d'objets peut résoudre ce problème. Si ce n'est pas le cas, vous devrez créer un scénario de test entièrement reproductible (y compris les données) ; publiez-le ici ou soumettez-le au support Oracle. Cela peut prendre plusieurs heures pour le retrouver.
  2. Bogue. Très rarement, un bogue peut entraîner l'échec des requêtes lors du retour ou de la modification des données. Encore une fois, un cas de test entièrement reproductible est nécessaire pour diagnostiquer cela, et cela peut prendre un certain temps.
  3. Fonctionnalité qui change SQL Il existe plusieurs façons de modifier de manière transparente les instructions SQL. Examinez la base de données privée virtuelle (VPD), DBMS_ADVANCED_REWRITE et le cadre de traduction SQL.

Pour exclure le #3, le code ci-dessous vous montre l'une des mauvaises façons de faire cela, et comment le détecter. Commencez par créer le schéma et certaines données :

CREATE TABLE TRACKING (
  A_ID NUMBER,
  D_CODE NUMBER,
  HOD NUMBER,
  ADR_CNT NUMBER,
  TTL_CNT NUMBER,
  CREATED DATE,
  MODIFIED DATE
);
CREATE INDEX HOD_D_CODE_IDX ON TRACKING (HOD, D_CODE);
CREATE UNIQUE INDEX TRACKING_PK ON TRACKING (A_ID, D_CODE, HOD);
CREATE INDEX MOD_DATE_IDX ON TRACKING (MODIFIED);
ALTER TABLE TRACKING ADD CONSTRAINT TRACKING_PK PRIMARY KEY (A_ID, D_CODE, HOD);

insert into tracking values (1,2,3,4,5,sysdate,sysdate);
commit;

Au début, tout fonctionne comme prévu :

SQL> SELECT * FROM TRACKING;

      A_ID     D_CODE        HOD    ADR_CNT    TTL_CNT CREATED   MODIFIED
---------- ---------- ---------- ---------- ---------- --------- ---------
         1          2          3          4          5 17-JUN-16 17-JUN-16

SQL> SELECT COUNT(1) FROM TRACKING;

  COUNT(1)
----------
         1

Alors quelqu'un fait ceci :

begin
  sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
    'april_fools',
    'SELECT COUNT(1) FROM TRACKING',
    'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
    false);
end;
/

Maintenant, les résultats sont "faux":

SQL> ALTER SESSION SET query_rewrite_integrity = trusted;

Session altered.

SQL> SELECT COUNT(1) FROM TRACKING;

  COUNT(1)
----------
         0

Cela peut être probablement détecté en regardant le plan d'explication. Dans l'exemple ci-dessous, le Prédicat 2 - filter(ROWNUM=1) est un indice que quelque chose ne va pas, puisque ce prédicat n'est pas dans la requête d'origine. Parfois, la section "Notes" du plan d'explication vous dira exactement pourquoi il a été transformé, mais parfois, elle ne donne que des indices.

SQL> explain plan for SELECT COUNT(1) FROM TRACKING;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
Plan hash value: 1761840423

------------------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                |     1 |     2 |     1   (0)| 00:00:01 |
|   1 |  VIEW             |                |     1 |     2 |     1   (0)| 00:00:01 |
|*  2 |   COUNT STOPKEY   |                |       |       |            |          |
|   3 |    INDEX FULL SCAN| HOD_D_CODE_IDX |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(ROWNUM=1)

15 rows selected.

(Sur une note sans rapport - utilisez toujours COUNT(*) au lieu de COUNT(1) . COUNT(1) est un vieux mythe qui ressemble à une programmation culte du cargo.)