sql >> Database >  >> RDS >> Oracle

Oracle Select * retourneert rijen maar Select count(1) retourneert 0

Verkeerde resultaten kunnen worden veroorzaakt door corruptie, bugs en functies die SQL-instructies stilletjes wijzigen.

  1. Corrupte index. Zeer zelden raakt een index beschadigd en komen de gegevens uit een index niet overeen met de gegevens uit een tabel. Dit veroorzaakt onverwachte resultaten wanneer het queryplan verandert en een index wordt gebruikt, maar alles ziet er normaal uit voor verschillende query's die gebruikmaken van tabeltoegang. Soms kan dit eenvoudig worden opgelost door objecten opnieuw te bouwen. Als dit niet het geval is, moet u een volledig reproduceerbare testcase maken (inclusief gegevens); post het hier of verstuur het naar Oracle Support. Het kan vele uren duren om dit op te sporen.
  2. Bug. Zeer zelden kan een bug ertoe leiden dat query's mislukken bij het retourneren of wijzigen van gegevens. Nogmaals, een volledig reproduceerbare testcase is vereist om dit te diagnosticeren, en het kan even duren.
  3. Functie die SQL schakelt Er zijn een paar manieren om SQL-instructies transparant te wijzigen. Kijk naar Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE en het SQL Translation Framework.

Om #3 uit te sluiten, toont de onderstaande code je een van de slechte manieren om dit te doen, en hoe je het kunt detecteren. Maak eerst het schema en enkele gegevens:

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;

In het begin werkt alles zoals verwacht:

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

Dan doet iemand dit:

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

Nu zijn de resultaten "fout":

SQL> ALTER SESSION SET query_rewrite_integrity = trusted;

Session altered.

SQL> SELECT COUNT(1) FROM TRACKING;

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

Dit kan waarschijnlijk worden gedetecteerd door te kijken naar het legplan. In het onderstaande voorbeeld is het predikaat 2 - filter(ROWNUM=1) is een aanwijzing dat er iets mis is, aangezien dat predikaat niet in de oorspronkelijke zoekopdracht staat. Soms zal het gedeelte 'Opmerkingen' van het uitlegplan u precies vertellen waarom het is getransformeerd, maar soms geeft het alleen aanwijzingen.

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.

(Op een niet-gerelateerde opmerking - gebruik altijd COUNT(*) in plaats van COUNT(1) . COUNT(1) is een oude mythe die lijkt op programmering van cargocult.)



  1. Arabisch teken niet correct ingevoegd (zoals ????) in Oracle-database?

  2. MySQL-query, MAX() + GROUP BY

  3. Wanneer controleert Postgres unieke beperkingen?

  4. PostgreSQL-server wil niet afsluiten op Lion (Mac OS 10.7)