3

ご存知かもしれませんが、自己結合を使用してビューにインデックスを付けることはできません。技術的には自己結合でなくても、実際には同じテーブルの2つの結合ですらあります。マイクロソフトの何人かの人が回避策を思いついた。しかし、それはとても複雑で、私には理解できません!!!

この問題の解決策は次のとおりです:http://jmkehayias.blogspot.com/2008/12/creating-indexed-view-with-self-join.html

この回避策を適用したいビューは次のとおりです。

create VIEW vw_lookup_test
WITH SCHEMABINDING
AS
select
count_big(*) as [count_all],
awc_txt,
city_nm,
str_nm,
stru_no,
o.circt_cstdn_nm [owner],
t.circt_cstdn_nm [tech],
dvc.circt_nm,
data_orgtn_yr 
from 
((dbo.dvc 
join dbo.circt 
on dvc.circt_nm = circt.circt_nm) 
join dbo.circt_cstdn o
on circt.circt_cstdn_user_id = o.circt_cstdn_user_id)
join dbo.circt_cstdn t
on dvc.circt_cstdn_user_id = t.circt_cstdn_user_id
group by
awc_txt,
city_nm,
str_nm,
stru_no,
o.circt_cstdn_nm,
t.circt_cstdn_nm,
dvc.circt_nm,
data_orgtn_yr 
go

どんな助けでも大いに感謝されるでしょう!!!

よろしくお願いします!

編集:だから私はこれもうまくいくことがわかりました。最初のインデックス付きビューで1回、2番目の非インデックスビューで2回目にテーブルに参加していることに注意してください。

alter VIEW vw_lookup_owner_test2
WITH SCHEMABINDING  
AS 
select
count_big(*) as [countAll],
awc_txt,
city_nm,
str_nm,
stru_no,
dvc.circt_nm,
circt_cstdn_nm,
data_orgtn_yr,
dvc.circt_cstdn_user_id
from dbo.dvc 
join dbo.circt
on dvc.circt_nm = circt.circt_nm
join dbo.circt_cstdn o
on circt.circt_cstdn_user_id = o.circt_cstdn_user_id
group by
awc_txt,
city_nm,
str_nm,
stru_no,
dvc.circt_nm,
circt_cstdn_nm,
data_orgtn_yr,
dvc.circt_cstdn_user_id
go

CREATE UNIQUE CLUSTERED INDEX [idx_vw_lookup_owner2_test1] ON [dbo].[vw_lookup_owner_test2] 
(
    [awc_txt] ASC,
    [city_nm] ASC,
    [str_nm] ASC,
    [stru_no] ASC,
    [circt_nm] ASC,
    [circt_cstdn_nm] ASC,
    [data_orgtn_yr] ASC,
    [circt_cstdn_user_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

create view vw_lookup_dvc_loc
as
select
awc_txt,
city_nm,
str_nm,
stru_no,
circt_nm,
o.circt_cstdn_nm as [owner],
--o.circt_cstdn_user_id,
t.circt_cstdn_nm as tech,
data_orgtn_yr
from vw_lookup_owner_test2 o With (NOEXPAND)
join circt_cstdn t
on o.circt_cstdn_user_id = t.circt_cstdn_user_id
group by
awc_txt,
city_nm,
str_nm,
stru_no,
circt_nm,
o.circt_cstdn_nm,
data_orgtn_yr,
t.circt_cstdn_nm
--o.circt_cstdn_user_id

次に、必要に応じて、最初のビューで追加インデックスを作成できます。この解決策(またはその問題の回避策)が実際にパフォーマンスを向上させるかどうかはわかりませんが、お知らせします。

4

2 に答える 2

1

これが私がブログ投稿から得たものです

  • dbo.circt_cstdn に 2 回参加したいとしましょう。つまり、次のようなものが必要です。

             owner       tech
    rowA     a.nm        b.nm
    ...
    
  • 値を 2 列に取得する代わりに、値を 2 行 (上の行ごとに 2 つ) に取得し、追加の列を追加して、どの行がどの列に対応するかを示します。行 1.1 と行 1.2 のデータは同じであることに注意してください (名前と列を除く)。

             name   for
    row1.1   nm     owner
    row1.2   nm     tech
    ...
    
  • 次に、所有者と技術者の名前列の最大値をピボットします。注 - max 関数は、PIVOT (集計関数が必要) をだますためのものです。レコード所有者が 1 つしかない場合、同じ値を返す任意の集計関数を使用できます tech row1 nm nm ...

クエリに対してこれを行うと

  1. このようなテーブル d を作成します

     i
     1
     2
    
  2. これでクエリの最初の部分をクロス結合します

    SELECT 
         count_big(*) as [count_all], 
         awc_txt, 
         city_nm, 
         str_nm, 
         stru_no, 
         dvc.circt_nm, 
         data_orgtn_yr
    FROM  
         dbo.dvc  
         INNER JOIN dbo.circt on dvc.circt_nm = circt.circt_nm
         CROSS JOIN dbo.d  
    GROUP BY
         awc_txt, city_nm, str_nm, stru_no, dvc.circt_nm, data_orgtn_yr, d.i
    
  3. Di が 1 の場合は行を所有者に使用し、Di が 2 の場合は技術を使用します。

    SELECT 
         count_big(*) as [count_all], 
         awc_txt, 
         city_nm, 
         str_nm, 
         stru_no, 
         dvc.circt_nm, 
         data_orgtn_yr,
         Case 
             WHEN d.i = 1 THEN 'Owner'
             WHEN d.i = 2 THEN 'Tech'
         END
    FROM  
         dbo.dvc  
         INNER JOIN dbo.circt on dvc.circt_nm = circt.circt_nm
         CROSS JOIN dbo.d 
    GROUP BY
         awc_txt, city_nm, str_nm, stru_no, dvc.circt_nm, data_orgtn_yr, 
         Case 
             WHEN d.i = 1 THEN 'Owner'
             WHEN d.i = 2 THEN 'Tech'
         END  
    
  4. ここで、nm 列を追加します。名前を取得するには、所有者行 (di = 1) の場合は circt で、技術行 (di = 2) の場合は dvc で circt_cstdn に参加します。注 - これを結合条件に入れて、ここでショートカットを試みました。うまくいかない場合は、ブログ投稿の方法を試してください (circt.circt_cstdn_user_idまたはdvc.circt_cstdn_user_id で結合を行い、WHERE 句を使用して除外します)。

    SELECT 
         count_big(*) as [count_all], 
         awc_txt, 
         city_nm, 
         str_nm, 
         stru_no, 
         dvc.circt_nm, 
         data_orgtn_yr,
         Case 
             WHEN d.i = 1 THEN 'Owner'
             WHEN d.i = 2 THEN 'Tech'
         END as PersonType,
         circt_cstdn_nm
    FROM  
         dbo.dvc  
         INNER JOIN dbo.circt on dvc.circt_nm = circt.circt_nm
         CROSS JOIN dbo.d 
         INNER JOIN dbo.circt_cstdn on circt_cstdn_user_id = 
              CASE
                   WHEN d.i = 1 THEN circt.circt_cstdn_user_id
                   WHEN d.i = 2 THEN dvc.circt_cstdn_user_id
              END
    GROUP BY
         awc_txt, city_nm, str_nm, stru_no, dvc.circt_nm, data_orgtn_yr, 
         Case 
             WHEN d.i = 1 THEN 'Owner'
             WHEN d.i = 2 THEN 'Tech'
         END,
         circt_cstdn_nm
    
  5. それを使用してビューを作成し、インデックスを作成します

    create VIEW vw_lookup_test_imed
    WITH SCHEMABINDING 
    AS
        <<query above>>  
    GO
    
    spell to create INDEX
    
  6. ここで PIVOT して PersonType 列を Owner 列と Tech 列に変換します

    SELECT 
         count_all, 
         awc_txt, 
         city_nm, 
         str_nm, 
         stru_no, 
         dvc.circt_nm, 
         data_orgtn_yr,
         [Owner], 
         [Tech] 
    FROM 
    ( 
         SELECT 
              count_all, 
              awc_txt, 
              city_nm, 
              str_nm, 
              stru_no, 
              dvc.circt_nm, 
              data_orgtn_yr,
              PersonType,
              circt_cstdn_nm
         FROM dbo.vw_lookup_test_imed WITH (NOEXPAND) 
    ) src 
    PIVOT 
    ( 
         MAX(circt_cstdn_nm) 
         FOR PersonType IN ([Owner], [Tech]) 
    ) pvt 
    

構文エラーがある場合 (現在、データベースにアクセスできないことが原因であることが多いはずです)、お知らせください。

于 2010-06-16T07:32:53.940 に答える
0

この JOIN 構文はひどいもので、MS Access に由来すると思います。うーん。私はあなたが使用することをお勧めします:

select
count_big(*) as [count_all],
awc_txt,
city_nm,
str_nm,
stru_no,
o.circt_cstdn_nm [owner],
t.circt_cstdn_nm [tech],
dvc.circt_nm,
data_orgtn_yr 

-- HERE
from dbo.dvc
join dbo.circt on (dvc.circt_nm = circt.circt_nm) 
join dbo.circt_cstdn o on (circt.circt_cstdn_user_id = o.circt_cstdn_user_id)
join dbo.circt_cstdn t on (dvc.circt_cstdn_user_id = t.circt_cstdn_user_id)

group by
awc_txt,
city_nm,
str_nm,
stru_no,
o.circt_cstdn_nm,
t.circt_cstdn_nm,
dvc.circt_nm,
data_orgtn_yr 

この構文はより簡潔で理解しやすく、SQL Server、Firebird、Oracle、MySQL などで認識されています。これで、「テーブル」間の関係がよくわかります。同じ「テーブル」に 2 回以上参加する場合は、それぞれに別名を付ける必要があります。ある行では、「circt_cstdn」が「o」としてエイリアス化されています。別の行では、「circt_cstdn」は「t」としてエイリアスされています。

JOIN の代わりに LEFT JOIN または INNER JOIN を使用することをお勧めします。

于 2010-06-15T23:36:03.093 に答える