Query Running Differently pada SQL 2005 vs SQL 2008R2

9

Di kantor saya, kami memiliki permintaan yang sangat jelek, tetapi berjalan cukup baik dalam produksi dan dalam lingkungan pengembangan (masing-masing 20 detik, dan 4 detik). Namun dalam lingkungan pengujian kami dibutuhkan lebih dari 4 jam. SQL2005 (+ tambalan terbaru) berjalan dalam produksi dan pengembangan. SQL2008R2 sedang berjalan dalam pengujian.

Saya melihat pada Rencana Kueri, dan itu menunjukkan bahwa SQL2008R2 menggunakan TempDB, melalui Table Spool (lazy spool) untuk menyimpan baris yang dikembalikan dari server yang terhubung. Langkah selanjutnya adalah menunjukkan Nested Loops (kiri anti semi bergabung) sebagai memakan 96,3% dari permintaan. Garis antara dua operator adalah 5,398MB!

Rencana kueri untuk SQL 2005 tidak menunjukkan penggunaan tempdb dan tidak ada penggunaan Left Anti Semi Join.

Di bawah ini adalah kode sanitasi dan rencana pelaksanaan rencana 2005 di atas, 2008R2 di bawah.

Apa yang menyebabkan drastis melambat dan berubah? Saya mengharapkan untuk melihat rencana eksekusi yang berbeda, sehingga tidak mengganggu saya. Perlambatan dramatis dalam waktu permintaan adalah apa yang mengganggu saya.

Apakah saya harus melihat perangkat keras yang mendasarinya, karena versi 2008R2 menggunakan tempdb, saya harus melihat cara mengoptimalkan penggunaan itu?

Apakah ada cara yang lebih baik untuk menulis kueri?

Terima kasih untuk bantuannya.

    INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE 
   (
    Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
    AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
    AND NOT Alias2.FirstName IS NULL 
    AND NOT Alias2.LastName  IS NULL
   ) OR (
    Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
    AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
    AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
    AND NOT Alias2.Familyname IS NULL
    AND NOT Alias2.Child1Name IS NULL
   ) OR (
    Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
    AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
    AND NOT Alias2.StepFamilyName IS NULL
    AND NOT Alias2.StepFamilyNameChild1 IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
   )  
 ) AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )

SQL-2005


SQL2008R2

:: EDIT :: Mengeksekusi kueri dari contoh SQL2005 yang berbeda, cukup banyak rencana eksekusi yang sama dengan "yang bagus". Masih tidak yakin bagaimana kedua versi 2005 berjalan lebih baik ke server terkait 2008R2, dibandingkan dengan 2008R2 ke 2008R2.

Meskipun saya tidak menyangkal bahwa kode tersebut dapat menggunakan beberapa pekerjaan, jika kode tersebut yang menjadi masalah, bukankah saya akan melihat rencana eksekutif yang sama di semua uji coba saya? Terlepas dari versi SQL?

:: EDIT :: Saya telah menerapkan SP1 dan CU3 untuk kedua instance 2008R2, masih belum ada dadu. Saya secara khusus mengatur kolokasi di server tertaut, tidak ada dadu. Saya secara khusus mengatur izin pengguna saya untuk menjadi sysadmin pada kedua contoh, tanpa dadu. Saya juga ingat internal sql server 2008 saya dan pemecahan masalah, kita akan melihat apakah saya bisa melacak ini bagaimana caranya.

Terima kasih semuanya atas bantuan dan tipsnya.

:: EDIT :: Saya telah melakukan berbagai perubahan izin ke server yang ditautkan. Saya telah menggunakan login SQL, login domain, saya telah menyamar sebagai pengguna, saya telah menggunakan opsi "dibuat menggunakan konteks keamanan ini". Saya telah membuat pengguna di kedua sisi server tertaut yang memiliki hak sysadmin di server. Saya kehabisan ide.

Saya masih ingin tahu mengapa SQL2005 mengeksekusi query yang sangat berbeda dari SQL2008R2. Jika itu adalah permintaan yang buruk, saya akan melihat waktu berjalan 4 jam pada SQL2005 dan SQL2008R2.

RateControl
sumber

Jawaban:

5

Saya ingin Anda mengerjakan ulang kueri.

Anda memiliki masalah sargability, dan bahkan menggunakan panggilan fungsi skalar di sana, yang juga akan mengganggu kueri. Anda mungkin ingin membuat kolom yang dihitung FullName pada Table2 dan menempatkan indeks pada itu, pastikan indeks Anda TERMASUK FirstName dan LastName. Anda juga harus menambahkan indeks yang membantu yang lain

Juga, buat fungsi bernilai tabel inline untuk melakukan fungsionalitas "RemoveNonLetter" Anda, dan ulang permintaan Anda untuk menggunakannya, mungkin menggunakan BERLAKU seperti yang saya lakukan di sini.

Dan tentu saja periksa bug yang dimaksud jawaban Paulus .

INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FullName)) AS fn (FullName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FamilyName)) AS famn (FamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.Child1Name)) AS c1n (Child1Name)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyName)) AS sfn (StepFamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyNameChild2)) AS sfnc2 (StepFamilyNameChild2)
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FullName = fn.FullName
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FamilyName = famn.FamilyName AND Alias2.Child1Name = c1n.Child1Name
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.StepFamilyName = sfn.StepFamilyName AND Alias2.StepFamilyNameChild1 = sfnc2.StepFamilyNameChild2
 ) 
 AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )
;
Rob Farley
sumber
6

Menambah jawaban sebelumnya, alasan regresi rencana mungkin disebabkan oleh bug estimasi kardinalitas yang diketahui ketika rencana menyertakan Anti Semi Join. Lihat KB 2222998

Dengan asumsi paket 2005 menghasilkan kinerja yang dapat diterima, Anda mungkin menemukan membawa server ke versi yang menyertakan perbaikan itu (dan mengaktifkan TF4199 untuk mengaktifkannya) akan mengembalikan Anda ke paket 'baik'.

Yang mengatakan, ada banyak peluang lain untuk meningkatkan permintaan itu, jadi ini mungkin saat yang tepat untuk berkonsentrasi melakukan itu.

Paul White 9
sumber
5

Saya menyarankan agar data jarak jauh digulung secara lokal karena salah satunya

  1. Pengaturan Server yang Ditautkan (seperti collation) tidak sama
  2. Collation lokal tidak sama dengan remote, meskipun pengaturan server terkait
  3. Kueri tidak dapat berjalan dengan benar dari jarak jauh karena izin

Untuk poin 1, lihat sp_serveroption
Dan untuk poin 2, tetapi juga periksa server / db.

Untuk poin 3, lihat ini dari Linchi Shea:

Anda meminta SQL Server untuk memproses semua data secara lokal, sesuai jawaban saya di sini: Implikasi kinerja menggunakan OPENQUERY dalam tampilan

Edit

Pada tampilan kedua, saya melihat 2 panggilan jarak jauh pada paket "bagus" dan bukan satu. Ini menegaskan apa yang saya katakan di sini

gbn
sumber
Maaf atas keterlambatan yang lama. 1: Saya memeriksa pengaturan server yang ditautkan, keduanya sama: Saya juga memeriksa dan secara implisit mengatur susunan properti server yang ditautkan ke server jarak jauh. 3: Konteks keamanan yang masih saya kerjakan dalam melakukan pengujian A / B. Saya masih keras kepala pada logika di balik rencana eksekutif yang berbeda secara drastis. Dari server R2 ke server R2 hanya menjalankan pilih (menarik lebih dari 150 ribu baris), kemudian melakukan gabungan. Di mana sebagai 2005 ke R2 itu melakukan pemilihan, dan bergabung di server jauh. Konteks keamanan untuk kedua skenario adalah sama.
RateControl
3

+1 pada Coba Menulis ulang komentar kueri Anda dari datagod.

Saya juga bertanya-tanya apakah Anda menabrak masalah izin di sisi server terkait yang mengarah ke perlambatan ini. Saya membuat blog tentang perlambatan server terkait ini beberapa waktu lalu. Mungkin layak memverifikasi perms (apakah itu server SQL linked? Atau DBMS lain? Jika yang terakhir, maka Anda tidak akan mendapatkan statistik yang bagus di seluruh)

Apakah Anda memiliki SQL Server 2005 di lingkungan pengujian untuk mencoba kueri ini dan mengesampingkan lingkungan?

Sudahkah Anda membangun kembali statistik sejak peningkatan?

Mike Walsh
sumber
3

Ada begitu banyak masalah dengan perbandingan ini ... Saya hanya tidak tahu harus mulai dari mana.

  1. Dapatkan spesifikasi yang tepat untuk produksi dan mesin uji Anda.

  2. Tentukan tautan jaringan antara berbagai pengait yang terhubung di kedua lingkungan. Apakah kecepatannya sama? Apakah server terletak bersebelahan di kedua lingkungan?

  3. Apakah ada cara sama sekali bahwa Anda bisa menulis ulang kueri untuk TIDAK menggunakan server yang tertaut? Bergabung dengan tabel di server membuat Anda rentan terhadap perubahan topologi, dan sangat lambat dalam banyak kasus.

  4. Penggunaan TIDAK dan OR biasanya mengarah ke pemindaian tabel penuh. Cobalah menulis ulang kueri.

datagod
sumber