Kötü bir yürütme planını Azure SQL Veritabanı'ndan nasıl kaldırabilirim?


12

DBCC FREEPROCCACHEAzure SQL DB'de çalışmaz. Başka bir planı, bir üretim sistemine zarar vermeyecek bir şekilde kendini önbellekten atmaya zorlayabilir miyim (yani, sadece willy nilly tabloları değiştiremiyorum)? Bu özellikle Entity Framework tarafından oluşturulan SQL içindir, bu nedenle bunlar kendi kendini yöneten depolanmış prokslar değildir - etkin bir şekilde dinamik SQL'dir.

(Kaynak kötü endekslerdi -> kötü istatistikler vb. Bunların hepsi düzeltildi, ancak kötü bir plan ortadan kalkmayacak.)

GÜNCELLEME: İlk önce oraya @ mrdenny'nin çözümünü seçtim. Bununla birlikte, işi gerçekleştirmek için @Aaron Bertrand'ın senaryosunu başarıyla kullanıyorum. Yardım için herkese teşekkürler !!


Azure'da bir sp_recompile yapabilir misiniz?
mrdenny

Evet. Tam olarak ne üzerinde çalışardım? Kayıtlı procumuz yok. Bu dinamik SQL koştu sp_executesql.
Jaxidian

2
Onu masanın üzerinde çalıştırabilirsiniz ve bu tabloyu kullanan planları temizlemelidir. (Bu işe yararsa ben bir cevap yapacağım.)
mrdenny

1
Ben sadece bir tablo üzerinde denedim ve görünüşe göre işlem sırasında bir işlemde tabloyu kilitler. Sadece 24 kayıt ile 10 sütunlu bir tabloda denedim ve bitirmek bir dakika sürdü. Bu süre zarfında, tabloyu sorgulayamadım. Üretimdeki gerçek tablolarımızda böyle bir şey çalıştıramam!
Jaxidian

1
Kahretsin, bu bir serseri. Null olabilecek bir sütun eklemek gibi bir şema değişikliği yapmanız ve sonra bırakmanız gerekecek gibi görünüyor. Bu önbelleği de siler ve çabuk olmalıdır. Test kesin olarak söyleyecektir.
mrdenny

Yanıtlar:


12

Azure SQL artık bunu doğrudan destekliyor

Azure SQL Veritabanı, geçerli kullanıcı veritabanının proc önbelleğinin herhangi bir saldırı olmadan doğrudan temizlenmesini destekler:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

ek bilgi

Aşağıdaki komut dosyası ( Shannon Gowen tarafından ) işlemi adım adım izlemek için kullanılabilir:

-- run this script against a user database, not master
-- count number of plans currently in cache
select count(*) from sys.dm_exec_cached_plans;

-- Executing this statement will clear the procedure cache in the current database, which means that all queries will have to recompile.
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

-- count number of plans in cache now, after they were cleared from cache
select count(*) from sys.dm_exec_cached_plans;

-- list available plans
select * from sys.dm_exec_cached_plans;

Ben henüz denemedim ama bu aslında işlevsel ise, o zaman bu muhtemelen 2017 başından itibaren "en iyi" cevaptır. Bunun için teşekkürler - bu konuda hiçbir ipucu yoktu! :-)
Jaxidian

Bu (bir Premium DB üzerinde) denedim ve çalıştı.
Remi Lemarchand

Bunu güncellenmiş bir "Kabul Edilen Cevap" olarak işaretledim ancak henüz kendim test etmedim. Bunu doğrudan Todd ve Remi'nin geri bildirimlerine dayandırıyorum. Herkese teşekkürler!
Jaxidian

Sadece tekrar ziyaret etmek için bunu kullandım ve benim için iyi çalıştı! Todd'un cevabını zenginleştirmek için bazı ek senaryolar ekliyorum, ancak yazısı kafasına çiviyi vurdu.
Jaxidian

Bu benim için çalışmıyor gibi görünüyor - sadece yürütür ama listeler hala dolu - SQL Azure'dayım - sorun ne olabilir?
Dirk Boer

12

Bugün bunu yapmanın açık bir yolu yoktur, ancak bu kalıcı bir senaryo değildir (DBCC komutu hala desteklenmemektedir, ancak Query Store'da okunmaktadır ). Şema değişikliği isabeti kabul edilebilir olsa bile, istediğiniz şey olmayabilir, çünkü sadece kötü olanla değil , temeldeki nesneyle ilgili tüm planları geçersiz kılacaktır .

Bunun için kredi aramamak, ancak birden çok tabloya karşı aynı işlemi gerçekleştirmek için dinamik SQL oluşturmak oldukça kolaydır:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER TABLE '
  + QUOTENAME(SCHEMA_NAME([schema_id])) 
  + '.' + QUOTENAME(name) + ' ADD fake_column INT NULL;
  ALTER TABLE ' 
  + QUOTENAME(SCHEMA_NAME([schema_id]))
  + '.' + QUOTENAME(name) + ' DROP COLUMN fake_column;'
FROM sys.tables
--WHERE name IN, LIKE, etc.

PRINT @sql;

-- if the command > 8K, you can see the second chunk e.g.

PRINT SUBSTRING(@sql, 8001, 8000);

--EXEC sys.sp_executesql @sql;

( Bu "dinamik SQL uzunluğu" sorunu hakkında bir ipucu yazdım ...)


Benim durumumda, hepsini kaldırmak, kötü olanları orada bırakmak için çok tercih edilir. Söylediğin için teşekkürler. Bana özellikleri söyleyemeyeceğinizi biliyorum ama konuşamayacağınız şeyler hakkında konuşmaktan artık ne zaman kısıtlanamayacağınızı söyleyebilir misiniz ? ;-)
Jaxidian

Bu da sınıflandırılmış, üzgünüm. :-)
Aaron Bertrand

Bağlantı ile ne demek istediğinizden emin değilim. Demek istediğim, nvarchar(max)değişkeninizin 4000 karakterden, 8000 karakterden sonra bir sınıra geçmesi varchar(max). Tam komut dosyasını çalıştırıyorum. ~ 450 masa var, bu yüzden kolayca vurduk (~ 30/60 masa). varchar(max)geçerli bir sözdizimidir, yalnızca ile aynıdır varchar(8000)ve nvarchar(max)aynıdır nvarchar(4000).
Jaxidian

3
Evet, PRINTemir verdiğinizde sadece 8000 bayt gösteriyor. Bu PRINTkomutun bir sınırlamasıdır, Azure değil. Komutu çalıştırırsanız, her şeyi görsel olarak inceleyemeseniz bile çalışır.
Aaron Bertrand

... doh, üzgünüm, bence haklısın! Beni düzelttiğin için teşekkürler! Karınız 25 dakika önce ayrılmanızı beklediğinde böyle olur ... ;-) Bu senaryo benim için mükemmel çalışıyor!
Jaxidian

6

Tabloya boş bir sütun ekleyin ve sütunu bırakın. Bu, SQL'i bu nesnenin önbelleğini temizlemeye zorlar.

Tüm tabloları yapmaya gelince, bir imleç hile yapmalıdır. 'Zzzzzz_go_away' gibi bir tabloda asla bulunmayacak bir sütun adı kullanmanız yeterlidir.


4

Azure SQL Veritabanı şu anda desteklemediğinden DBCC FREEPROCCACHE, bir yürütme planını önbellekten el ile kaldıramazsınız. Ancak, sorgu ( ALTER TABLE/ ALTER VIEW) tarafından başvurulan bir tablo veya görünümde değişiklik yaparsanız , plan önbellekten kaldırılır. ( Referans .)


Burada gönderdiğin her şeyi zaten biliyordum. Bu ne bir saklı yordam ne de bir görünüm, bu yüzden bunlardan birini değiştiremiyorum. Yük altındayken ve herhangi bir duruşa veya tablonun kilitlenmesine neden olmadan, tablolarımı tetiklemek için önemsiz bir şekilde nasıl değiştirebilirim?
Jaxidian

1
Muhtemelen sahte bir sütun ekleyip bırakabilirsiniz. Bu, planı önbellekten kaldıracaktır. Masa ne kadar büyük?
Kin Shah

Bu, mrdenny tarafından önerildiği gibi çözüm oldu. Yardım için teşekkürler!! :-)
Jaxidian

1
Teşekkürler ... Sadece birkaç saniye kısa sürede .. stackexchange başka bir yazı cevap oldu ...
Kin Shah

1

Tüm yürütme planını temizlemek için şunu kullanın:

    SET NOCOUNT ON

DECLARE @lcl_name VARCHAR(100)
DECLARE @addcolumnSql nVARCHAR(MAX)
DECLARE @dropcolumnSql nVARCHAR(MAX)

DECLARE cur_name CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U'
OPEN cur_name
FETCH NEXT FROM cur_name INTO @lcl_name
WHILE @@Fetch_status = 0
BEGIN
set @addcolumnSql = 'alter table [' + @lcl_name + '] add temp_col_to_clear_exec_plan bit'
EXEcute sp_executesql @addcolumnSql
print @addcolumnSql
set @dropcolumnSql = 'alter table [' + @lcl_name + '] drop column temp_col_to_clear_exec_plan'
EXEcute sp_executesql @dropcolumnSql
print @dropcolumnSql
--  EXEC (@lcl_name )
FETCH NEXT FROM cur_name INTO @lcl_name
END
CLOSE cur_name
DEALLOCATE cur_name
SET NOCOUNT OFF

Bir tabloyu değiştirir veya referans veren bir görünüm alırsanız, yürütme planı temizlenir.

Burada biraz daha açıklanmıştır http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.