sql >> Databáze >  >> RDS >> Oracle

Oracle Select * vrátí řádky, ale Select count(1) vrátí 0

Nesprávné výsledky mohou být způsobeny poškozením, chybami a funkcemi, které tiše mění příkazy SQL.

  1. Index poškození. Velmi zřídka se index poškodí a data z indexu se neshodují s daty z tabulky. To způsobí neočekávané výsledky, když se změní plán dotazů a použije se index, ale vše vypadá normálně pro různé dotazy, které používají přístup k tabulce. Někdy to může vyřešit jednoduchá přestavba objektů. Pokud ne, budete muset vytvořit plně reprodukovatelný testovací případ (včetně dat); buď jej zveřejněte zde, nebo jej odešlete podpoře Oracle. Vysledování může trvat mnoho hodin.
  2. Chyba. Velmi zřídka může chyba způsobit selhání dotazů při návratu nebo změně dat. K diagnóze je opět nutný plně reprodukovatelný testovací případ a může to chvíli trvat.
  3. Funkce, která přepíná SQL Existuje několik způsobů, jak transparentně změnit příkazy SQL. Podívejte se na Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE a SQL Translation Framework.

Abychom vyloučili číslo 3, níže uvedený kód vám ukáže jeden ze zlých způsobů, jak toho dosáhnout, a jak to zjistit. Nejprve vytvořte schéma a některá data:

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;

Zpočátku vše funguje podle očekávání:

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

Pak někdo udělá toto:

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

Nyní jsou výsledky "špatné":

SQL> ALTER SESSION SET query_rewrite_integrity = trusted;

Session altered.

SQL> SELECT COUNT(1) FROM TRACKING;

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

To lze pravděpodobně zjistit pohledem na plán vysvětlení. V níže uvedeném příkladu je predikát 2 - filter(ROWNUM=1) je vodítko, že něco není v pořádku, protože tento predikát není v původním dotazu. Někdy vám část "Poznámky" plánu vysvětlení řekne přesně, proč byl transformován, ale někdy poskytuje pouze vodítka.

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.

(Nesouvisející poznámka - vždy použijte COUNT(*) místo COUNT(1) . COUNT(1) je starý mýtus, který vypadá jako programování kultu nákladu.)



  1. Je mysql_real_escape_string() nefunkční?

  2. Vytváření plánů údržby databáze

  3. Vraťte řádky, které mají v Postgresql maximálně jeden sloupec

  4. FNDCPASS &AFPASSWD