Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Oracle Select * mengembalikan baris tetapi Select count(1) mengembalikan 0

Hasil yang salah dapat disebabkan oleh kerusakan, bug, dan fitur yang secara diam-diam mengubah pernyataan SQL.

  1. Indeks yang rusak. Sangat jarang indeks rusak dan data dari indeks tidak cocok dengan data dari tabel. Ini menyebabkan hasil yang tidak diharapkan ketika rencana kueri berubah dan indeks digunakan, tetapi semuanya tampak normal untuk kueri berbeda yang menggunakan akses tabel. Terkadang hanya dengan membangun kembali objek dapat memperbaikinya. Jika tidak, Anda harus membuat kasus uji yang sepenuhnya dapat direproduksi (termasuk data); baik posting di sini atau kirimkan ke Dukungan Oracle. Perlu waktu berjam-jam untuk melacaknya.
  2. Bug. Sangat jarang bug dapat menyebabkan kueri gagal saat mengembalikan atau mengubah data. Sekali lagi, kasus uji yang sepenuhnya dapat direproduksi diperlukan untuk mendiagnosis hal ini, dan ini dapat memakan waktu cukup lama.
  3. Fitur yang mengalihkan SQL Ada beberapa cara untuk mengubah pernyataan SQL secara transparan. Lihat Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE, dan SQL Translation Framework.

Untuk mengesampingkan # 3, kode di bawah ini menunjukkan kepada Anda salah satu cara jahat untuk melakukan ini, dan cara mendeteksinya. Pertama, buat skema dan beberapa 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;

Pada awalnya, semuanya berjalan seperti yang diharapkan:

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

Kemudian seseorang melakukan ini:

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

Sekarang hasilnya "salah":

SQL> ALTER SESSION SET query_rewrite_integrity = trusted;

Session altered.

SQL> SELECT COUNT(1) FROM TRACKING;

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

Ini mungkin dapat dideteksi dengan melihat rencana penjelasan. Pada contoh di bawah, Predikat 2 - filter(ROWNUM=1) adalah petunjuk bahwa ada sesuatu yang salah, karena predikat itu tidak ada dalam kueri asli. Terkadang bagian "Catatan" dari rencana penjelasan akan memberi tahu Anda dengan tepat mengapa itu diubah, tetapi terkadang hanya memberikan petunjuk.

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.

(Pada catatan yang tidak terkait - selalu gunakan COUNT(*) bukannya COUNT(1) . COUNT(1) adalah mitos lama yang terlihat seperti pemrograman kultus kargo.)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Membuang Blok Data

  2. masalah hibernasi oracle10g

  3. Disebabkan oleh:java.sql.SQLException:ORA-01795:jumlah maksimum ekspresi dalam daftar adalah 1000?

  4. Bergabung terlalu lama

  5. Karakter escape Oracle SQL (untuk '&')