5

多くのレコード(> 100'000)を持つテーブルAがあり、テーブルBにはAと同じ列があり、ほぼ同じデータ量があるとします。1つの巧妙なselectステートメントで、テーブルAのすべてのレコードまたはテーブルBのすべてのレコードを取得できる可能性はありますか?

パフォーマンスのために、現在使用しているアプローチにはあまり満足していません。

select
     column1
    ,column2
    ,column3
from (
    select 'A' as tablename, a.* from table_a a
    union
    select 'B' as tablename, b.* from table_b b
) x
where 
    x.tablename = 'A'
4

4 に答える 4

2

次の解決策を試すことができます。テーブル tmp1 ('A' = 'A') からのみ選択します

select
  *
from
  tmp1
where
  'A' = 'A'

union all

select
  *
from
  tmp2
where
  'B' = 'A'

SQL Fiddle デモはこちら 実行計画をチェック

予定

于 2012-11-22T13:49:58.433 に答える
2

率直に言って、あなたのアプローチは標準SQLの唯一のアプローチのようです。

を に変更すると、パフォーマンスが大幅に向上UNIONUNION ALLます。はUNION、データを返す前に、両方のテーブルからデータを読み取り、重複を排除する必要があります。

UNION ALL重複を排除しません。これがどの程度パフォーマンスを向上させるかは、データベース エンジンと、場合によってはターニング パラメータに依存します。

実は、別の可能性があります。うまくいくかどうかはわかりませんが、試してみてください:

select *
from ((select const.tableName, a.*
       from A cross join
            (select 'A' as tableName where x.TableName = 'A')
      ) union all
      (select const.tableName, b.*
       from B cross join
            (select 'B' as tableName where x.TableName = 'B')
      )
     ) t

約束はできません。しかし、アイデアは、1 行または 0 行のテーブルにクロス結合することです。これは MySQL では機能しませWHEREFROM。他のデータベースでは、 などのテーブル名が必要になる場合がありますdual。これにより、サブクエリにレコードが含まれていない場合、クエリ エンジンはテーブルの読み取りを完全に最適化することができます。もちろん、SQL エンジンに最適化の機会を与えたからといって、そうなるわけではありません。

また、「*」は、特にユニオンでは悪い考えです。しかし、それは質問の焦点では​​ないので、私はそれを残しました.

于 2012-11-21T14:44:48.987 に答える
1

もう少しコンテキストがないと、何が欲しいかを正確に伝えるのは難しいですが、おそらくこのようなものがうまくいくでしょうか?

DECLARE @TableName nvarchar(15);
DECLARE @Query nvarchar(50);

SELECT @TableName = YourField
FROM YourTable
WHERE ...

SET @Query = 'SELECT * FROM ' + @TableName

EXEC @Query

構文は、使用している RDBMS や、より具体的には何を達成しようとしているのかによって少し異なる場合がありますが、正しい方向へのプッシュになる可能性があります。

于 2012-11-21T13:42:29.930 に答える
1

これを実行してパフォーマンスを維持する適切な方法には、物理​​テーブルの設計を変更する必要があります。

インジケータ列を保持する各テーブルに列を追加し、その列にチェック制約を追加できる場合、クエリで「パーティション」の除去を実現できます。

DDL:

create table table_a (
   c1 ...
  ,c2 ...
  ,c3 ...
  ,table_ind char(1) not null generated always as 'A'
  ,constraint ck_table_ind check (table_ind = 'A')
);

create table table_b (
   c1 ...
  ,c2 ...
  ,c3 ...
  ,table_ind char(1) not null generated always as 'B'
  ,constraint ck_table_ind check (table_ind = 'B')
);

create view v1 as (
    select * from table_a 
    union all 
    select * from table_b
);

クエリを実行すると、DB2 オプティマイザはチェック制約を使用して述語に一致するselect c1,c2,c3 from v1 where table_ind = 'A'行がないことを認識し、アクセス プランからテーブルを完全に除外します。table_btable_ind = 'A'

これは、DB2 for Linux/UNIX/Windows が Range Partitioning をサポートする前に使用されていました (場合によっては現在も使用されています)。この手法の詳細については、2002 年に IBM DB2 開発者によって書かれたこの研究論文 [PDF]を参照してください。

于 2012-11-22T02:20:23.073 に答える