Permintaan terhadap sys.schemas dan sys.synonim berjalan sangat lambat untuk satu pengguna


8

Skenario: SQL Server 2014 (v12.0.4100.1)

Layanan .NET menjalankan kueri ini:

SELECT name, base_object_name 
FROM sys.synonyms 
WHERE schema_id IN (SELECT schema_id 
                    FROM sys.schemas 
                    WHERE name = N'XXXX')
ORDER BY name

... yang mengembalikan sekitar 6500 baris tetapi sering kali keluar setelah 3+ menit. Di XXXXatas bukan 'dbo'.

Jika saya menjalankan kueri ini dalam SSMS sebagai UserA, kueri kembali dalam waktu kurang dari satu detik.

Ketika dijalankan sebagai UserB (yang merupakan cara layanan .NET terhubung), kueri membutuhkan waktu 3-6 menit , dan memiliki% CPU sebesar 25% (dari 4 core) sepanjang waktu.

UserA adalah Login Domain dalam peran sysadmin.

UserB adalah SQL Login dengan:

EXEC sp_addrolemember N'db_datareader', N'UserB'
EXEC sp_addrolemember N'db_datawriter', N'UserB'
EXEC sp_addrolemember N'db_ddladmin', N'UserB'
GRANT EXECUTE TO [UserB]
GRANT CREATE SCHEMA TO [UserB]
GRANT VIEW DEFINITION TO [UserB]

Saya bisa menduplikasi ini dalam SSMS dengan membungkus SQL di atas dalam satu Execute as...Revertblok, sehingga kode .NET keluar dari gambar.

Rencana eksekusi terlihat sama. Saya membuat XML dan hanya ada sedikit perbedaan (CompileTime, CompileCPU, CompileMemory).

Statistik IO semua tidak menunjukkan bacaan fisik:

Nilai tabel 'sysobjes'. Pindai hitungan 0, bacaan logis 19970, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca 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.
Tabel 'Meja Kerja'. 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.
Tabel 'sysschobjs'. Pindai hitungan 1, bacaan logis 9122, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Tabel 'sysclsobjs'. Pindai menghitung 0, bacaan logis 2, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

Status menunggu XEvent (untuk permintaan ~ 3 menit) adalah:

+ --------------------- + ------------ + -------------- -------- + ------------------------------ + ---------- ------------------- +
| Jenis Tunggu | Tunggu Hitungan | Total Waktu Tunggu (ms) | Total Waktu Tunggu Sumberdaya (ms) | Total Waktu Tunggu Sinyal (ms) |
+ --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- +
| SOS_SCHEDULER_YIELD | 37300 | 427 | 20 | 407 |
| NETWORK_IO | 5 | 26 | 26 | 0 |
| IO_COMPLETION | 3 | 1 | 1 | 0 |
+ --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- +

Jika saya menulis ulang kueri (dalam SSMS, saya tidak memiliki akses ke Kode Aplikasi) ke

declare @id int 
SELECT @id=schema_id FROM sys.schemas WHERE name = N'XXXX'
SELECT a.name, base_object_name FROM sys.synonyms a
WHERE schema_id = @id
ORDER BY name

kemudian UserB berjalan pada kecepatan (cepat) yang sama dengan UserA.

Jika saya menambahkan db_ownerke UserB, maka, sekali lagi, kueri berjalan <1 detik.

Skema yang dibuat melalui templat ini:

DECLARE @TranName VARCHAR(20)
SELECT @TranName = 'MyTransaction'

BEGIN TRANSACTION @TranName
GO

IF NOT EXISTS (SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
        WHERE SCHEMA_NAME = '{1}')
BEGIN
    EXEC('CREATE SCHEMA [{1}]')
    EXEC sp_addextendedproperty @name='User', @value='{0}', @level0type=N'Schema', @level0name=N'{1}'
END
GO

{2}

COMMIT TRANSACTION MyTransaction;
GO

Dan {2} adalah, saya percaya, daftar Sinonim yang dibuat dalam skema itu.

Profil Permintaan pada dua titik ke dalam permintaan:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Saya sudah membuka tiket dengan Microsoft.

Kami juga mencoba menambahkan UserB ke db_owner, dan kemudian mengambil DENYsemua hak istimewa yang kami ketahui terkait dengan db_owner. Hasilnya adalah permintaan yang cepat. Entah kami melewatkan sesuatu (sepenuhnya mungkin), atau ada pemeriksaan khusus untuk db_ownerperan tersebut.

Jawaban:


5

Anda mungkin ingin menulis ulang kueri Anda sebagai berikut (Saya menggunakan dbodaripada XXXXagar saya menemukan beberapa sinonim pada basis data pengujian saya). Ini mirip dengan penulisan ulang yang Anda temukan lebih efisien, tetapi menghindari keharusan mendeklarasikan variabel dan menggunakan dua kueri.

SELECT name, base_object_name 
FROM sys.synonyms 
WHERE schema_id = SCHEMA_ID(N'dbo')
ORDER BY name

Ini menghasilkan rencana seperti berikut:

masukkan deskripsi gambar di sini

Satu hal yang sangat menarik tentang Filteroperator dalam paket ini adalah ia memiliki predikat yang melakukan pemeriksaan internal has_access(). Filter ini menghapus objek apa pun yang tidak memiliki izin cukup untuk dilihat oleh akun saat ini. Namun, pemeriksaan ini dilakukan hubung singkat (yaitu, selesai jauh lebih cepat) jika Anda adalah anggota db_ownerperan, yang dapat menjelaskan perbedaan kinerja yang Anda lihat.

masukkan deskripsi gambar di sini

Ini adalah paket permintaan untuk permintaan awal Anda. Perhatikan bahwa semua sinonim pada database ( 1,126dalam kasus saya, tetapi kemungkinan lebih banyak dalam kasus Anda) melewati has_access()filter yang sangat mahal , meskipun hanya 2sinonim yang cocok dengan skema. Dengan menggunakan kueri yang disederhanakan di atas, kami dapat memastikan bahwa has_access()hanya dipanggil untuk sinonim yang cocok dengan kueri Anda, bukan untuk semua sinonim dalam database.

masukkan deskripsi gambar di sini


Menggunakan sys.dm_exec_query_profiles untuk mengeksplorasi lebih lanjut

Seperti yang disarankan Martin, kami dapat mengonfirmasi bahwa pemeriksaan has_access () adalah hambatan signifikan dengan menggunakan sys.dm_exec_query_profilesSQL Server 2014+. Jika saya menjalankan kueri berikut menggunakan db_ownerakun pada database dengan ~ 700K objek, kueri tersebut akan ~500ms:

SELECT COUNT(*)
FROM sys.objects

Saat dijalankan dengan akun yang bukan db_owner, kueri yang sama ini memakan waktu sekitar delapan menit! Berjalan dengan rencana aktual dan menggunakan prosedur p_queryProgress yang saya tulis untuk membantu parse sys.dm_exec_query_profilesoutput lebih mudah, kita dapat melihat bahwa hampir semua waktu pemrosesan dihabiskan untuk Filteroperator yang melakukan has_access()pemeriksaan:

masukkan deskripsi gambar di sini


Masalah TokenAndPermUserStore? Dalam hal ini artikel KB ini dapat membantu support.microsoft.com/en-gb/kb/955644
Martin Smith

@ MartinSmith Sangat menarik, saya tidak mengetahui access check cache bucket countdan access check cache quotaopsi konfigurasi sebelumnya. Harus bermain-main dengan itu sedikit.
Geoff Patterson

Saya tidak yakin bahwa cache ini relevan dengan kasus di sini. Saya hanya ingat itu menyebabkan masalah di masa lalu.
Martin Smith

1
@ MartinSmith Meskipun pengaturan itu tidak berdampak, ada sesuatu yang menarik terjadi dengan cache. Sepertinya keberadaan cache itu merugikan. Misalnya, jika saya menjalankan WHILE(1=1) BEGIN DBCC FREESYSTEMCACHE ('TokenAndPermUserStore') WAITFOR DELAY '00:00:05' ENDdalam satu lingkaran selamanya, kueri diselesaikan dalam waktu kurang dari 2 menit vs 8 menit.
Geoff Patterson

1
Terima kasih semuanya - tanggapan balik dari Microsoft menggemakan komentar di atas, dan penulisan ulang permintaan adalah solusi terbaik. Ternyata has_access () memiliki hubungan pendek di awal untuk menguji db_owner atau sysadmin dan menghasilkan perbedaan waktu yang besar.
James

0

Jika ini masih hidup - kami memiliki masalah yang sama - tampaknya jika Anda adalah dbo atau sysadmin maka akses apa pun ke sys.objects (atau semacamnya) - maka itu instan tanpa pemeriksaan terhadap objek individual.

jika itu adalah db_datareader rendah maka ia harus memeriksa setiap objek pada gilirannya ... itu disembunyikan dalam rencana kueri karena ini berperilaku lebih seperti fungsi daripada tampilan / tabel

rencananya terlihat sama, tetapi melakukan hal yang berbeda di balik tenda


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.