Apakah mungkin untuk memaksa pengoptimal untuk menghilangkan tabel yang tidak relevan dalam tampilan yang dipartisi ini?

22

Saya menguji arsitektur yang berbeda untuk tabel besar dan satu saran yang saya lihat adalah menggunakan tampilan dipartisi, di mana tabel besar dipecah menjadi serangkaian lebih kecil, tabel "dipartisi".

1 , 2 , 3 , 4

Dalam menguji pendekatan ini, saya telah menemukan sesuatu yang tidak masuk akal bagi saya. Ketika saya memfilter pada "kolom partisi" pada tampilan fakta, pengoptimal hanya mencari di tabel yang relevan. Selain itu, jika saya memfilter pada kolom itu di tabel dimensi, pengoptimal menghilangkan tabel yang tidak perlu.

Namun, jika saya memfilter pada beberapa aspek lain dari dimensi pengoptimal mencari PK / CI dari setiap tabel dasar.

Inilah pertanyaan yang dimaksud:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];

filter fakta pada tombol

filter redup pada tombol

filter redup pada aspek

Berikut tautan ke sesi SQL Sentry Plan Explorer.

Saya sedang mengerjakan benar-benar mempartisi tabel yang lebih besar untuk melihat apakah saya mendapatkan penghapusan partisi untuk merespons dengan cara yang sama.

Saya mendapatkan penghapusan partisi untuk kueri (sederhana) yang memfilter pada aspek dimensi.

Sementara itu, inilah salinan database yang hanya statistik:

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

Penaksir kardinalitas "lama" mendapatkan rencana yang lebih murah, tetapi itu karena perkiraan kardinalitas yang lebih rendah pada setiap indeks yang dicari (tidak perlu).

Saya ingin tahu apakah ada cara untuk mendapatkan pengoptimal menggunakan kolom kunci saat memfilter dengan aspek lain dari dimensi sehingga dapat menghilangkan mencari di tabel yang tidak relevan.

Versi SQL Server:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)
swasheck
sumber
Hanya FYI .. aliran stat terakhir rusakCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Kin Shah
Sepertinya skrip untuk basis data statistik saja terpotong. Saya mencoba mengklik "lihat file lengkap" dan mengunduh zip, tetapi bagaimanapun saya tidak memiliki statistik untuk ObservationDatestabel. Saya tidak mendapatkan rencana yang sama dengan Paul, bahkan dengan 4199, dan saya pikir inilah sebabnya.
Geoff Patterson
@ GeoffPatterson berfungsi untuk saya. apakah Anda mengklik tautan ke file mentah? gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/... namun, seperti yang dicatat Kin, aliran statistik terakhir rusak: /
swasheck
Saya mengklik tautan untuk file mentah. Script berfungsi (kecuali masalah yang dicatat Kin), tetapi tidak mengandung logika apa pun untuk membuat statistik ObservationDates. Saya akhirnya berjalan UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000secara manual untuk mendapatkan rencana yang ditunjukkan Paul.
Geoff Patterson
aneh. membuat database baru dan menjalankan skrip yang saya punya objek statistik (well, mereka indeks) ObservationDatesjadi saya tidak yakin apa yang terjadi dengan itu. juga, saya tidak bisa mendapatkan rencana paul dihasilkan juga. Saya akan mencoba pembaruan untuk melihat.
swasheck

Jawaban:

10

Aktifkan tanda jejak 4199.

Saya juga harus mengeluarkan:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

untuk mendapatkan rencana yang ditunjukkan di bawah ini. Statistik untuk tabel ini tidak ada dari unggahan. Angka 73.049 berasal dari informasi Kardinalitas Tabel di lampiran Plan Explorer. Saya menggunakan SQL Server 2014 SP1 CU4 (build 12.0.4436) dengan dua prosesor logis, memori maksimum diatur ke 2048 MB, dan tidak ada jejak jejak selain 4199.

Anda kemudian harus mendapatkan rencana eksekusi yang menampilkan penghapusan partisi dinamis:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);

Paket fragmen:

Rencanakan fragmen

Ini mungkin terlihat lebih buruk, tetapi Filter adalah semua filter start-up . Contoh predikat adalah:

Saring properti

Per iterasi dari loop, predikat start-up diuji, dan hanya jika itu mengembalikan true adalah Indeks Clustered Carilah di bawahnya dieksekusi. Oleh karena itu, penghapusan partisi dinamis.

Hal ini mungkin tidak cukup seefisien penghapusan statis, terutama jika rencana tersebut sejajar.

Anda mungkin perlu mencoba petunjuk seperti MAXDOP 1, FAST 1atau FORCESEEKpada tampilan untuk mendapatkan paket yang sama. Pilihan penetapan biaya pengoptimal dengan tampilan yang dipartisi (seperti tabel yang dipartisi) bisa rumit.

Intinya adalah Anda memerlukan rencana yang menampilkan filter start-up untuk mendapatkan penghapusan partisi dinamis dengan tampilan yang dipartisi.


Pertanyaan dengan USE PLANpetunjuk yang tersemat : (via gist.github.com):

Paul White mengatakan GoFundMonica
sumber
1
Info bagus, terima kasih Paul! Saya bertanya-tanya setelah saya menulis jawaban saya mengapa tidak ada cara SQL Server dapat melakukan penghapusan jenis ini. Ternyata ada, saya hanya belum melihatnya sebelumnya!
Geoff Patterson
6

Pengamatan saya selalu bahwa Anda harus menentukan nilai (atau rentang nilai) untuk kolom partisi secara eksplisit dalam kueri untuk mendapatkan "penghapusan tabel" dalam tampilan yang dipartisi. Ini didasarkan pada pengalaman menggunakan tampilan dipartisi dalam produksi dari SQL Server 2000 hingga SQL Server 2014.

SQL Server tidak memiliki konsep loop join operator di mana mesin dapat secara dinamis mengarahkan pencarian langsung ke tabel yang tepat di sisi dalam loop berdasarkan nilai baris di sisi luar loop. Namun, seperti jawaban Paul menjelaskan , ada kemungkinan rencana dengan filter start-up untuk secara dinamis melewati tabel yang tidak relevan di sisi dalam loop dalam waktu yang konstan (sebagai lawan logaritmik dengan benar-benar melakukan pencarian).

Perhatikan bahwa untuk tabel yang dipartisi, jenis pencarian ini (ke partisi tertentu) didukung.

Jika Anda tetap menggunakan tampilan yang dipartisi, opsi lain adalah untuk membagi kueri Anda menjadi beberapa kueri, seperti:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)

Ini menghasilkan rencana berikut. Sekarang ada kueri tambahan yang mengenai tabel dimensi, tetapi kueri di atas tabel fakta (mungkin jauh lebih besar) dioptimalkan.

masukkan deskripsi gambar di sini

Geoff Patterson
sumber
Apakah efek yang sama akan tercapai jika Anda memasukkan kueri pertama ke dalam kuota kedua tanpa bantuan variabel?
Andriy M
@AndriyM Jika saya memahami Anda dengan benar, jawabannya tidak, efek yang sama tidak akan tercapai dan rencana kueri akan menyentuh semua tabel dalam tampilan yang dipartisi jika Anda mencoba untuk menggabungkan dua pertanyaan. Jika Anda menjalankan kueri pertama, lalu tempelkan nilai 20000101dan 20051231alih-alih variabel (atau lakukan sesuatu yang serupa melalui dua kueri terpisah di aplikasi Anda), maka ya, efek yang sama akan dicapai tanpa menggunakan variabel.
Geoff Patterson