Operasi Agregasi dengan Pandangan Mengabaikan Indeks [ditutup]

8

Skenario

Sekali waktu ada database Pementasan di sebuah perusahaan kecil yang berpartisipasi dalam proses ETL, bertindak sebagai katalog penerima untuk berbagai format file dari sejumlah sumber pihak ketiga. E ditangani melalui paket DTS, dengan beberapa struktur kontrol untuk audit atau kontrol, tetapi dianggap "Cukup Baik" dan untuk semua maksud dan tujuan, itu.

Data yang disediakan oleh bagian E dimaksudkan untuk konsumsi oleh aplikasi tunggal, dikembangkan dan dikelola oleh segelintir programmer muda dan mampu. Meskipun kurang memiliki pengalaman atau pengetahuan tentang teknik pergudangan data saat itu, mereka menetapkan dan menciptakan proses T dan L mereka sendiri dari kode aplikasi. Terobosan maju, para insinyur perangkat lunak pemula menemukan apa yang orang luar mungkin sebut "roda kurang ideal," tetapi dengan "Cukup Baik" sebagai tingkat layanan yang selalu ada, mereka mampu menyediakan kerangka kerja operasional.

Untuk sementara waktu, semua baik di dunia yang sangat erat, dengan katalog Pementasan berpesta pada data selusin pihak ketiga, pada gilirannya mendapat umpan dari aplikasi. Seiring bertambahnya aplikasi, begitu juga selera, tetapi dengan pengembang ksatria putih yang terampil mengawasi sistem, selera ini ditangani dengan cepat dan dalam banyak kasus, bahkan dengan baik.

Tetapi zaman keemasan tidak bisa bertahan selamanya, tentu saja. Dengan kemakmuran yang diberikan oleh aplikasi yang sukses, bisnis tumbuh dan berkembang. Ketika ia tumbuh, lingkungan Pementasan dan aplikasi dipaksa untuk tumbuh bersamanya. Untuk semua kewaspadaan mereka, segelintir pengembang pahlawan tidak bisa mengimbangi mempertahankan sistem yang sekarang luas, dan konsumen menjadi berhak atas data mereka. Bukan lagi soal apa yang mereka butuhkan atau bahkan inginkan, tetapi rakyat merasa bahwa mereka layak mendapatkannya, menuntut lebih banyak lagi.

Berbekal sedikit lebih dari pundi-pundi penuh barang curian, bisnis menjangkau ke pasar, mempekerjakan pengembang dan administrator untuk membantu mendukung sistem yang terus berkembang. Tentara bayaran dari setiap etos berbondong-bondong ke perusahaan, tetapi dengan lonjakan pertumbuhan ini tidak banyak yang menghalangi bimbingan ahli yang tersedia. Pengembang dan administrator baru berjuang untuk memahami seluk-beluk suite buatan rumah, sampai frustrasi mengakibatkan perang habis-habisan. Masing-masing departemen mulai berusaha untuk menyelesaikan setiap masalah sendirian, melakukan lebih banyak untuk bekerja melawan satu sama lain daripada bekerja dengan satu sama lain. Satu proyek atau inisiatif akan dilaksanakan dalam beberapa cara yang berbeda, masing-masing sedikit berbeda dari yang berikutnya. Ketegangan dari semuanya terbukti terlalu banyak untuk beberapa ksatria putih dan ketika mereka jatuh, kekaisaran hancur. Segera, sistem berantakan,

Terlepas dari transformasi bidang-bidang janji ini ke kode spageti berdarah, perusahaan tetap bertahan. Lagi pula, "Cukup Baik."

Tantangan

Beberapa perubahan rezim lagi dan mempekerjakan tenaga kemudian, saya menemukan diri saya dalam pekerjaan perusahaan. Sudah bertahun-tahun sejak perang besar, tetapi kerusakan yang terjadi masih sangat terlihat. Saya telah berhasil mengatasi beberapa kelemahan dalam bagian E dari sistem dan menambahkan beberapa tabel kontrol sementara dengan kedok meningkatkan paket DTS ke SSIS, yang sekarang sedang digunakan oleh beberapa profesional pergudangan data aktual saat mereka membuat normal dan penggantian T dan L yang didokumentasikan.

Rintangan pertama adalah mengimpor data dari file pihak ketiga dengan cara yang tidak akan memotong nilai-nilai atau mengubah tipe data asli, tetapi juga menyertakan beberapa kunci kontrol untuk memuat ulang dan membersihkan. Ini semua baik dan bagus, tetapi aplikasi harus dapat mengakses tabel-tabel baru ini secara mulus dan transparan. Paket DTS dapat mengisi tabel, yang kemudian langsung dibaca oleh aplikasi. Pembaruan SSIS perlu dilakukan secara paralel karena alasan QA, tetapi paket-paket baru ini mencakup berbagai kunci kontrol dan juga meningkatkan skema partisi, belum lagi perubahan metadata yang sebenarnya saja bisa cukup signifikan untuk menjamin tabel baru sekaligus, jadi tabel baru digunakan untuk paket SSIS baru.

Dengan impor data yang andal kini berfungsi dan digunakan oleh tim pergudangan, tantangan sesungguhnya adalah melayani data baru ke aplikasi yang mengakses lingkungan Pementasan secara langsung, dengan dampak minimal (alias "Tidak") pada kode aplikasi. Untuk ini, saya telah memilih untuk menggunakan tampilan, mengubah nama tabel seperti dbo.DailyTransactionuntuk dbo.DailyTranscation_LEGACYdan menggunakan kembali dbo.DailyTransactionnama objek untuk tampilan, yang secara efektif hanya memilih semuanya dari sekarangLEGACYmeja yang ditunjuk. Karena memuat ulang tahun data yang terkandung dalam tabel ini bukan merupakan pilihan dari perspektif bisnis, karena tabel yang dipopulasi dan dipartisi SSIS masuk ke produksi, impor DTS lama dimatikan dan aplikasi harus dapat mengakses data baru di tabel baru juga. Pada titik ini, pandangan diperbarui untuk memilih data dari tabel baru (katakanlah,, dbo.DailyTransactionCompletemisalnya) ketika tersedia dan pilih dari tabel lama ketika tidak.

Akibatnya, sesuatu seperti berikut sedang dilakukan:

CREATE VIEW dbo.DailyTransaction
AS  SELECT  DailyTransaction_PK, FileDate, Foo
    FROM    dbo.DailyTransactionComplete
    UNION ALL
    SELECT  DailyTransaction_PK, FileDate, Foo
    FROM    dbo.DailyTransaction_LEGACY l
    WHERE NOT EXISTS (  SELECT  1
                        FROM    dbo.DailyTransactionComplete t
                        WHERE   t.FileDate = l.FileDate );

Meskipun logis, ini tidak bekerja dengan baik dalam sejumlah kasus agregasi, umumnya menghasilkan rencana eksekusi yang melakukan pemindaian indeks penuh terhadap data dalam tabel legacy. Ini mungkin baik untuk beberapa lusin juta rekaman, tetapi tidak begitu banyak untuk beberapa lusin juta rekaman. Karena yang terakhir sebenarnya adalah kasusnya, saya harus menggunakan ... "kreatif," yang menuntun saya untuk menciptakan tampilan yang diindeks.

Berikut ini adalah sedikit kasus uji yang telah saya siapkan, termasuk FileDatekunci kontrol yang telah porting ke DateCode_FKport yang kompatibel dengan Data Warehouse untuk menggambarkan betapa sedikit sekali saya peduli tentang pertanyaan terhadap tabel baru yang dapat ditagih untuk sementara waktu:

USE tempdb;
GO

SET NOCOUNT ON;
GO

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'DailyTransaction_LEGACY'
                    AND type = 'U' )
BEGIN
    --DROP TABLE dbo.DailyTransaction_LEGACY;
    CREATE TABLE dbo.DailyTransaction_LEGACY
    (
        DailyTransaction_PK         BIGINT IDENTITY( 1, 1 ) NOT NULL,
        FileDate                    DATETIME NOT NULL,
        Foo                         INT NOT NULL
    );

    INSERT INTO dbo.DailyTransaction_LEGACY ( FileDate, Foo )
    SELECT  DATEADD( DAY, ( 1 - ROW_NUMBER() 
                OVER( ORDER BY so1.object_id ) - 800 ) % 1000, 
                CONVERT( DATE, GETDATE() ) ),
            so1.object_id % 1000 + so2.object_id % 1000
    FROM    sys.all_objects so1
    CROSS JOIN sys.all_objects so2;

    ALTER TABLE dbo.DailyTransaction_LEGACY
    ADD CONSTRAINT PK__DailyTrainsaction
        PRIMARY KEY CLUSTERED ( DailyTransaction_PK )
    WITH ( DATA_COMPRESSION = PAGE, FILLFACTOR = 100 );
END;
GO

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'DailyTransactionComplete'
                    AND type = 'U' )
BEGIN
    --DROP TABLE dbo.DailyTransactionComplete;
    CREATE TABLE dbo.DailyTransactionComplete
    (
        DailyTransaction_PK            BIGINT IDENTITY( 1, 1 ) NOT NULL,
        DateCode_FK                    INTEGER NOT NULL,
        Foo                            INTEGER NOT NULL
    );

    INSERT INTO dbo.DailyTransactionComplete ( DateCode_FK, Foo )
    SELECT  TOP 100000
            CONVERT( INTEGER, CONVERT( VARCHAR( 8 ), DATEADD( DAY, 
                ( 1 - ROW_NUMBER() OVER( ORDER BY so1.object_id ) ) % 100, 
                GETDATE() ), 112 ) ),
            so1.object_id % 1000
    FROM    sys.all_objects so1
    CROSS JOIN sys.all_objects so2;

    ALTER TABLE dbo.DailyTransactionComplete
    ADD CONSTRAINT PK__DailyTransaction
        PRIMARY KEY CLUSTERED ( DateCode_FK, DailyTransaction_PK )
    WITH ( DATA_COMPRESSION = PAGE, FILLFACTOR = 100 );        
END;
GO

Pada sandbox lokal saya, di atas membuat saya meja warisan dengan sekitar 4,4 juta baris dan tabel baru yang berisi 0,1 juta baris, dengan beberapa tumpang tindih dari DateCode_FK/ FileDatenilai.

A MAX( FileDate )terhadap tabel lawas tanpa indeks tambahan berjalan tentang apa yang saya harapkan.

SET STATISTICS IO, TIME ON;

DECLARE @ConsumeOutput        DATETIME;
SELECT  @ConsumeOutput = MAX( FileDate )
FROM    dbo.DailyTransaction_LEGACY;

SET STATISTICS IO, TIME OFF;
GO

Tabel 'DailyTransaction_LEGACY'. Pindai hitungan 1, bacaan logis 9228, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.

Waktu Eksekusi SQL Server: Waktu CPU = 889 ms, waktu yang berlalu = 886 ms.

Indeks Berkelompok, Warisan

Meletakkan indeks sederhana di atas meja membuat segalanya lebih baik. Masih memindai, tetapi memindai satu catatan, bukan 4,4 juta catatan. Saya senang dengan itu.

CREATE NONCLUSTERED INDEX IX__DailyTransaction__FileDate
    ON    dbo.DailyTransaction_LEGACY ( FileDate );

SET STATISTICS IO, TIME ON;

DECLARE @ConsumeOutput        DATETIME;
SELECT  @ConsumeOutput = MAX( FileDate )
FROM    dbo.DailyTransaction_LEGACY;

SET STATISTICS IO, TIME OFF;
GO

SQL Server menguraikan dan mengkompilasi waktu: Waktu CPU = 0 ms, waktu yang berlalu = 1 ms. Tabel 'DailyTransaction_LEGACY'. Pindai hitungan 1, bacaan logis 3, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

Waktu Eksekusi SQL Server: Waktu CPU = 0 ms, waktu yang berlalu = 0 ms.

Indeks non-cluster, Legacy

Dan sekarang, membuat tampilan sehingga pengembang tidak perlu mengubah kode apa pun karena itu tampaknya akan menjadi akhir dunia seperti yang kita kenal. Semacam bencana.

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'DailyTransaction'
                    AND type = 'V' )
BEGIN
    EXEC( 'CREATE VIEW dbo.DailyTransaction AS SELECT x = 1;' );
END;
GO

ALTER VIEW dbo.DailyTransaction
AS  SELECT  DailyTransaction_PK, FileDate = CONVERT( 
                DATETIME, CONVERT( VARCHAR( 8 ), DateCode_FK ), 112 ), Foo
    FROM    dbo.DailyTransactionComplete
    UNION ALL    
    SELECT  DailyTransaction_PK, FileDate, Foo
    FROM    dbo.DailyTransaction_LEGACY l
    WHERE   NOT EXISTS (    SELECT  1
                            FROM    dbo.DailyTransactionComplete t
                            WHERE   CONVERT( DATETIME, CONVERT( VARCHAR( 8 ),
                                        t.DateCode_FK ), 112 ) = l.FileDate );
GO

Ya, sub kueri itu sangat buruk, tapi ini bukan masalahnya dan saya mungkin hanya akan membuat kolom yang dihitung terus-menerus dan melemparkan indeks di atasnya untuk tujuan itu ketika masalah sebenarnya diselesaikan. Jadi tanpa basa-basi lagi,

Masalah

SET STATISTICS IO, TIME ON;

DECLARE @ConsumeOutput1        DATETIME;
SELECT  @ConsumeOutput1 = MAX( FileDate )
FROM    dbo.DailyTransaction;

SET STATISTICS IO, TIME OFF;
GO

SQL Server menguraikan dan mengkompilasi waktu: Waktu CPU = 0 ms, waktu yang berlalu = 4 ms. Tabel 'DailyTransaction_LEGACY'. Pindai hitungan 1, bacaan logis 11972, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0. Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0. Tabel 'Workfile'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca-depan lob 0. Tabel 'DailyTransactionComplete'. Pindai hitungan 2, bacaan logis 620, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

Waktu Eksekusi SQL Server: Waktu CPU = 983 ms, waktu yang berlalu = 983 ms.

Lihat Paket

Oh, begitu, Sql Server mencoba memberi tahu saya bahwa apa yang saya lakukan adalah bodoh. Sementara saya sebagian besar setuju, itu tidak mengubah kesulitan saya. Ini benar-benar berfungsi dengan sangat baik untuk kueri di mana tampilan FileDatepada dbo.DailyTransactiontermasuk dalam predikat, tetapi sementara MAXrencana itu cukup buruk, TOPrencana mengirimkan semuanya berjalan ke selatan. Selatan nyata.

SET STATISTICS IO, TIME ON;

SELECT  TOP 10 FileDate
FROM    dbo.DailyTransaction
GROUP BY FileDate 
ORDER BY FileDate DESC

SET STATISTICS IO, TIME OFF;
GO

Tabel 'DailyTransactionComplete'. Pindai hitungan 2, bacaan logis 1800110, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan lob baca-depan 0. Tabel 'DailyTransaction_LEGACY'. Pindai hitungan 1, bacaan logis 1254, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0. Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0. Tabel 'Workfile'. Pindai jumlah 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca-depan 0.

Waktu Eksekusi SQL Server: Waktu CPU = 109559 ms, waktu yang berlalu = 109664 ms.

Teratas

Saya sebutkan mendapatkan "kreatif" sebelumnya, yang mungkin menyesatkan. Apa yang ingin saya katakan adalah "lebih bodoh," sehingga upaya saya untuk membuat tampilan ini berfungsi selama operasi agregasi adalah untuk membuat tampilan pada tabel dbo.DailyTransactionCompletedan dbo.DailyTransaction_LEGACY, skema mengikat dan mengindeks yang terakhir, kemudian menggunakan tampilan tersebut di tampilan lain dengan NOEXPANDpetunjuk pada tampilan warisan. Sementara itu lebih atau kurang bekerja untuk apa yang perlu dilakukan untuk saat ini, saya menemukan seluruh "solusi" cukup mengecewakan, memuncak dengan yang berikut:

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'v_DailyTransactionComplete'
                    AND type = 'V' )
BEGIN
    EXEC( 'CREATE VIEW dbo.v_DailyTransactionComplete AS SELECT x = 1;' );
END;
GO

ALTER VIEW dbo.v_DailyTransactionComplete
AS  SELECT  DailyTransaction_PK, FileDate = CONVERT( DATETIME, 
                CONVERT( VARCHAR( 8 ), DateCode_FK ), 112 ), 
            Foo
    FROM    dbo.DailyTransactionComplete;
GO

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'v_DailyTransaction_LEGACY'
                    AND type = 'V' )
BEGIN
    EXEC( 'CREATE VIEW dbo.v_DailyTransaction_LEGACY AS SELECT x = 1;' );
END;
GO

ALTER VIEW dbo.v_DailyTransaction_LEGACY
WITH SCHEMABINDING
AS  SELECT  l.DailyTransaction_PK,
            l.FileDate,
            l.Foo,
            CountBig = COUNT_BIG( * )
    FROM    dbo.DailyTransaction_LEGACY l
    INNER JOIN dbo.DailyTransactionComplete n
        ON  l.FileDate <> CONVERT( DATETIME, CONVERT( VARCHAR( 8 ), 
                n.DateCode_FK ), 112 )
    GROUP BY l.DailyTransaction_PK,
            l.FileDate,
            l.Foo;
GO

CREATE UNIQUE CLUSTERED INDEX CI__v_DailyTransaction_LEGACY
    ON dbo.v_DailyTransaction_LEGACY ( FileDate, DailyTransaction_PK )
WITH ( DATA_COMPRESSION = PAGE, FILLFACTOR = 80 );
GO

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'DailyTransaction'
                    AND type = 'V' )
BEGIN
    EXEC( 'CREATE VIEW dbo.DailyTransaction AS SELECT x = 1;' );
END;
GO

ALTER VIEW dbo.DailyTransaction
AS  SELECT  DailyTransaction_PK, FileDate, Foo
    FROM    dbo.v_DailyTransactionComplete
    UNION ALL    
    SELECT  DailyTransaction_PK, FileDate, Foo
    FROM    dbo.v_DailyTransaction_LEGACY WITH ( NOEXPAND );
GO

Memaksa pengoptimal untuk menggunakan indeks yang disediakan oleh tampilan yang diindeks membuat MAXdan TOPmasalah hilang, tetapi harus ada cara yang lebih baik untuk mencapai apa yang saya coba lakukan di sini. Benar-benar ada saran / omelan akan sangat dihargai !!

SET STATISTICS IO, TIME ON;

DECLARE @ConsumeOutput1        DATETIME;
SELECT  @ConsumeOutput1 = MAX( FileDate )
FROM    dbo.DailyTransaction;

SET STATISTICS IO, TIME OFF;
GO

Tabel 'v_DailyTransaction_LEGACY'. Pindai hitungan 1, bacaan logis 3, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan lob baca-depan 0. Tabel 'DailyTransactionComplete'. Pindai hitungan 1, bacaan logis 310, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.

Waktu Eksekusi SQL Server: Waktu CPU = 31 ms, waktu yang berlalu = 36 ms.

SET STATISTICS IO, TIME ON;

DECLARE @ConsumeOutput1        DATETIME;
SELECT  TOP 10 @ConsumeOutput1 = FileDate
FROM    dbo.DailyTransaction
GROUP BY FileDate 
ORDER BY FileDate DESC

SET STATISTICS IO, TIME OFF;
GO

Tabel 'v_DailyTransaction_LEGACY'. Pindai hitungan 1, bacaan logis 101, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0. Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0. Tabel 'Workfile'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca-depan lob 0. Tabel 'DailyTransactionComplete'. Pindai hitungan 1, bacaan logis 310, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.

Waktu Eksekusi SQL Server: Waktu CPU = 63 ms, waktu yang berlalu = 66 ms.

TL; DR:

Bantu saya memahami apa yang harus saya lakukan untuk membuat kueri agregasi pada tampilan pertama yang saya sebutkan berjalan dalam jumlah waktu yang wajar dengan pemanfaatan sumber daya I / O yang masuk akal.

Avarkx
sumber
3
Tampilan yang tidak diindeks tidak menyimpan data apa pun, dan Anda tidak dapat mengindeks tampilan dengan subkueri, serikat pekerja, dll. Saya pikir Anda perlu mempertimbangkan mematerialisasi data dengan cara yang berbeda, seperti memisahkan tampilan itu menjadi dua tampilan dan kemudian menanyakan mereka, atau melewati tampilan sama sekali.
Aaron Bertrand
Saya pikir saya sedang berusaha untuk mencapai apa yang Anda sarankan, tetapi saya tidak sepenuhnya memahami apa yang perlu saya lakukan. Saya berpikir bahwa pandangan lama saya telah berhasil mengindeks dan terwujud sebagai bantuan-band tampaknya merupakan solusi yang cukup kotor untuk pembatasan sub-kueri, dan sementara itu bekerja kurang lebih dalam kondisi saat ini, sangat rentan terhadap penambahan cakupan creep. Saya bergulat dengan gagasan menyiapkan proses untuk mengisi tabel dasar yang sama sekali baru setelah impor terjadi dan mengubah tampilan untuk referensi itu.
Avarkx

Jawaban:

4

Menulis ulang NOT EXISTSsebagai DISTINCTgabungan ketimpangan memang memungkinkan tampilan diindeks, tetapi ada alasan bagus hal ini tidak umum dilakukan.

Rencana eksekusi yang dihasilkan untuk membangun indeks pada tampilan tidak dapat dihindari mengerikan. Ketidaksetaraan memaksa loop bersarang fisik bergabung, yang dengan pengecualian satu nilai, adalah persilangan silang. Mengurangi produk dengan grup yang berbeda atau setara dengan akan menghasilkan hasil yang benar, dengan asumsi kolom gabungan tidak dapat dibatalkan (seperti dalam kode contoh), tetapi tidak akan pernah efisien. Inefisiensi ini hanya akan bertambah buruk seiring berjalannya waktu dan tabel yang terlibat menjadi lebih besar.

Masalah serupa memengaruhi rencana eksekusi untuk pernyataan DML yang memengaruhi tabel yang direferensikan oleh tampilan (karena tampilan harus disinkronkan ke tabel dasar setiap saat di SQL Server). Lihatlah rencana eksekusi yang dihasilkan untuk menambah atau memodifikasi satu baris dalam tabel mana pun untuk melihat apa yang saya maksud.

Pada tingkat tinggi, masalah yang Anda hadapi adalah bahwa pengoptimal permintaan SQL Server tidak selalu menghasilkan rencana yang baik atas pandangan yang mencakup a UNION ALL. Banyak optimasi yang kami terima begitu saja (seperti MAX-> TOP (1)) sama sekali tidak dilaksanakan di seluruh serikat pekerja.

Untuk setiap masalah yang Anda selesaikan, Anda akan menemukan kasus lain di mana optimasi normal dan yang diharapkan tidak terjadi, menghasilkan rencana eksekusi dengan kinerja yang sangat buruk. Solusi yang jelas adalah untuk menghindari penggunaan kesatuan dalam pandangan. Bagaimana Anda menerapkan ini dalam kasus Anda tergantung pada perincian yang, meskipun ada perincian dalam pertanyaan, mungkin hanya diketahui oleh Anda.

Jika Anda memiliki ruang, salah satu solusinya adalah mempertahankan completedan legacymendasarkan tabel secara terpisah (termasuk logika yang tidak ada). Ini memang menghasilkan duplikasi data, dan dilengkapi dengan masalah sinkronisasi, tetapi dalam pengalaman saya ini jauh lebih mudah untuk diselesaikan dengan kuat daripada mencoba untuk mendapatkan pandangan serikat pekerja untuk menghasilkan rencana eksekusi yang baik untuk berbagai pertanyaan dalam semua situasi (atau bahkan sebagian besar).

SQL Server menyediakan sejumlah fitur untuk membantu sinkronisasi data, karena saya yakin Anda tahu, termasuk pelacakan perubahan, perubahan pengambilan data, pemicu ... dan seterusnya. Spesifikasi implementasi berada di luar forum ini. Poin penting adalah menyajikan pengoptimal dengan tabel dasar, bukan menyatukan semua tampilan.

Paul White 9
sumber
Terima kasih untuk Anda dan @AaronBertrand atas masukan Anda. Wawasan dan saran Anda sangat kami hargai! Saya mungkin akan berakhir secara manual memigrasi data tabel lama ke tabel baru sehingga saya dapat mengubah tampilan untuk tidak perlu lagi menyatukan dari tabel lama sama sekali. Secara teoritis, saya kemudian bisa menjatuhkan tabel warisan sama sekali. Akan ada tantangan lain dengan pendekatan ini, tetapi seperti yang telah Anda sebutkan, mungkin tantangan itu akan lebih dapat dikelola dalam jangka panjang karena apa yang saya lakukan jelas tidak akan berhasil dengan baik, selamanya.
Avarkx