8

毎日、リクエストはますます奇妙になります。

テーブル内のどの列にすべての行で同じ値が含まれているかを検出するためのクエリを作成するように依頼されました。私は、「これはプログラムで行う必要があるので、テーブルの N 回のパスではなく 1 回のパスで実行できるようにする必要があります」と言いました。

私は却下されました。

簡単に言えば。問題を示すこの非常に単純なクエリがあります。テスト セットを 4 回通過します。私は、すべての列にインデックスを追加したり、プログラムを書いたり、人間の一生をかけて実行したりすることを伴わない SQL Magery のアイデアを探しています。

そしてため息 どんなテーブルでも作業できる必要があります。

ご提案いただきありがとうございます。

WITH TEST_CASE AS
(
    SELECT 'X' A, 5 B, 'FRI' C, NULL D FROM DUAL UNION ALL
    SELECT 'X' A, 3 B, 'FRI' C, NULL D FROM DUAL UNION ALL
    SELECT 'X' A, 7 B, 'TUE' C, NULL D FROM DUAL 
),
KOUNTS AS 
(
    SELECT SQRT(COUNT(*)) S, 'Column A' COLUMNS_WITH_SINGLE_VALUES
    FROM TEST_CASE P, TEST_CASE Q
    WHERE P.A = Q.A OR (P.A IS NULL AND Q.A IS NULL)

    UNION ALL

    SELECT SQRT(COUNT(*)) S, 'Column B' COLUMNS_WITH_SINGLE_VALUES
    FROM TEST_CASE P, TEST_CASE Q
    WHERE P.B = Q.B OR (P.B IS NULL AND Q.B IS NULL)

    UNION ALL

    SELECT SQRT(COUNT(*)) S, 'Column C' COLUMNS_WITH_SINGLE_VALUES
    FROM TEST_CASE P, TEST_CASE Q
    WHERE P.C = Q.C OR (P.C IS NULL AND Q.C IS NULL)

    UNION ALL

    SELECT SQRT(COUNT(*)) S, 'Column D' COLUMNS_WITH_SINGLE_VALUES
    FROM TEST_CASE P, TEST_CASE Q
    WHERE P.D = Q.D OR (P.D IS NULL AND Q.D IS NULL)
)
SELECT COLUMNS_WITH_SINGLE_VALUES
FROM KOUNTS
WHERE S = (SELECT COUNT(*) FROM TEST_CASE)
4

4 に答える 4

10

このようなことを意味しますか?

WITH 
TEST_CASE AS
(
    SELECT 'X' A, 5 B, 'FRI' C, NULL D FROM DUAL UNION ALL
    SELECT 'X' A, 3 B, 'FRI' C, NULL D FROM DUAL UNION ALL
    SELECT 'X' A, 7 B, 'TUE' C, NULL D FROM DUAL 
)
select case when min(A) = max(A) THEN 'A'
            when min(B) = max(B) THEN 'B'
            when min(C) = max(C) THEN 'C'
            when min(D) = max(D) THEN 'D'
            else 'No one'
       end 
from TEST_CASE

これを編集 します:

WITH 
TEST_CASE AS
(
    SELECT 'X' A, 5 B, 'FRI' C, NULL D FROM DUAL UNION ALL
    SELECT 'X' A, 3 B, 'FRI' C, NULL D FROM DUAL UNION ALL
    SELECT 'X' A, 7 B, 'TUE' C, NULL D FROM DUAL 
)
select case when min(nvl(A,0)) = max(nvl(A,0)) THEN 'A ' end ||
       case when min(nvl(B,0)) = max(nvl(B,0)) THEN 'B ' end ||
       case when min(nvl(C,0)) = max(nvl(C,0)) THEN 'C ' end ||
       case when min(nvl(D,0)) = max(nvl(D,0)) THEN 'D ' end c

from TEST_CASE

おまけ: Null 値のチェックも追加したので、結果は A と D になります。

そして、あなたのためのSQLFiddle デモ

于 2013-10-31T16:32:59.727 に答える
8

オプティマイザ統計では、複数の異なる値を持つ列を簡単に識別できます。統計が収集された後、データ ディクショナリに対して単純なクエリを実行すると、ほぼ瞬時に結果が返されます。

ESTIMATE_PERCENT = 100 を使用する場合、結果は 10g でのみ正確になります。ESTIMATE_PERCENT = 100 または AUTO_SAMPLE_SIZE を使用する場合、結果は 11g+ で正確になります。

コード

create table test_case(a varchar2(1), b number, c varchar2(3),d number,e number);

--I added a new test case, E.  E has null and not-null values.
--This is a useful test because null and not-null values are counted separately.
insert into test_case
SELECT 'X' A, 5 B, 'FRI' C, NULL D, NULL E FROM DUAL UNION ALL
SELECT 'X' A, 3 B, 'FRI' C, NULL D, NULL E FROM DUAL UNION ALL
SELECT 'X' A, 7 B, 'TUE' C, NULL D, 1    E FROM DUAL;

--Gather stats with default settings, which uses AUTO_SAMPLE_SIZE.
--One advantage of this method is that you can quickly get information for many
--tables at one time.
begin
    dbms_stats.gather_schema_stats(user);
end;
/

--All columns with more than one distinct value.
--Note that nulls and not-nulls are counted differently.
--Not-nulls are counted distinctly, nulls are counted total.
select owner, table_name, column_name
from dba_tab_columns
where owner = user
    and num_distinct + least(num_nulls, 1) <= 1
order by column_name;

OWNER     TABLE_NAME   COLUMN_NAME
-------   ----------   -----------
JHELLER   TEST_CASE    A          
JHELLER   TEST_CASE    D          

パフォーマンス

11g では、このメソッドは mucio の SQL ステートメントと同じくらい高速かもしれません。のようなオプションcascade => falseは、インデックスを分析しないことでパフォーマンスを向上させます。

しかし、この方法の優れた点は、有用な統計も作成できることです。システムがすでに定期的に統計を収集している場合、大変な作業はすでに完了している可能性があります。

AUTO_SAMPLE_SIZE アルゴリズムの詳細

AUTO_SAMPLE_SIZE は 11g で完全に変更されました。個別値 (NDV) の数を推定するためにサンプリングを使用しません。代わりに、テーブル全体をスキャンし、ハッシュベースの個別のアルゴリズムを使用します。このアルゴリズムは、大量のメモリーや一時表領域を必要としません。テーブルの一部をソートするよりも、テーブル全体を読む方がはるかに高速です。Oracle Optimizer のブログでは、アルゴリズムについて適切に説明されています。詳細については、Amit Podder によるこのプレゼンテーションを参照してください。(次のセクションで詳細を確認したい場合は、その PDF をスキャンしてください。)

間違った結果の可能性

新しいアルゴリズムは単純なサンプリング アルゴリズムを使用していませんが、個別の値の数を 100% 正しくカウントすることはできません。個別の値の推定数が実際の値と異なるケースを簡単に見つけることができます。しかし、個別の値の数が明らかに不正確である場合、このソリューションでどのように信頼できるのでしょうか?

潜在的な不正確さは、ハッシュの衝突と概要の分割という 2 つの原因から生じます。概要の分割は不正確さの主な原因ですが、ここでは当てはまりません。13864 個の異なる値がある場合にのみ発生します。また、すべての値が破棄されることはありません。最終的な推定値は確実に 1 よりもはるかに大きくなります。

唯一の本当の懸念は、ハッシュの衝突で 2 つの異なる値が存在する可能性です。64 ビットのハッシュを使用すると、18,446,744,073,709,551,616 分の 1 という確率になります。残念ながら、私は彼らのハッシュ アルゴリズムの詳細を知りませんし、実際の確率も知りません。いくつかの簡単なテストと以前の実生活でのテストでは、衝突を生成できませんでした。(一部の統計操作ではデータの最初の N バイトのみを使用するため、私のテストの 1 つは大きな値を使用することでした。)

これは、テーブル内のすべての個別の値が衝突した場合にのみ発生することも考慮してください。たまたま衝突する 2 つの値のみを持つテーブルが存在する可能性はどれくらいですか? おそらく、宝くじに当選すると同時に隕石に当たる可能性よりもはるかに低いでしょう。

于 2013-11-03T07:23:48.197 に答える