sql >> データベース >  >> RDS >> Oracle

Oracle Select *は行を返しますが、Select count(1)は0を返します

    間違った結果は、SQLステートメントをサイレントに変更する破損、バグ、および機能によって引き起こされる可能性があります。

    1. 破損したインデックス。 インデックスが破損し、インデックスのデータがテーブルのデータと一致しないことはめったにありません。これにより、クエリプランが変更されてインデックスが使用されると予期しない結果が発生しますが、テーブルアクセスを使用するさまざまなクエリではすべてが正常に見えます。オブジェクトを再構築するだけでこれを修正できる場合があります。そうでない場合は、完全に再現可能なテストケース(データを含む)を作成する必要があります。ここに投稿するか、Oracleサポートに送信してください。これを追跡するのに何時間もかかる場合があります。
    2. バグ。 ごくまれに、データを返したり変更したりするときにバグが原因でクエリが失敗することがあります。繰り返しになりますが、これを診断するには完全に再現可能なテストケースが必要であり、時間がかかる場合があります。
    3. SQLを切り替える機能 SQLステートメントを透過的に変更する方法はいくつかあります。仮想プライベートデータベース(VPD)、DBMS_ADVANCED_REWRITE、およびSQL変換フレームワークを調べます。

    #3を除外するために、以下のコードは、これを行うための邪悪な方法の1つと、それを検出する方法を示しています。まず、スキーマといくつかのデータを作成します。

    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;
    

    最初は、すべてが期待どおりに機能します:

    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
    

    次に、誰かがこれを行います:

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

    結果は「間違っている」:

    SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
    
    Session altered.
    
    SQL> SELECT COUNT(1) FROM TRACKING;
    
      COUNT(1)
    ----------
             0
    

    これはおそらく、説明プランを見ることで検出できます。以下の例では、述語2 - filter(ROWNUM=1) その述語が元のクエリにないため、何かが間違っているという手がかりです。説明計画の「メモ」セクションに、それが変換された理由が正確に示される場合もありますが、手がかりが得られるだけの場合もあります。

    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.
    

    (無関係なメモについては、常にCOUNT(*)を使用してください COUNT(1)の代わりに 。 COUNT(1) カーゴカルトプログラミングのように見える古い神話です。)



    1. 更新ステートメントでのウィンドウ関数の使用

    2. SQLiteからPostgres(Heroku)GROUP BY

    3. プリペアドステートメントを使用した複雑なmysqlクエリの問題

    4. Rails:rake db:create:all(サーバーに接続できませんでした)