Gibt es außer dem Neustart von SQL Server eine Möglichkeit, das Zurücksetzen der SQLCLR-AppDomain zu erzwingen?

11

Ich möchte erzwingen, dass die von SQLCLR verwendete AppDomain zurückgesetzt wird. Wie kann ich das tun, außer die SQL Server-Instanz neu zu starten?

Justin Dearing
quelle
Ich bin mir nicht sicher, ob Sie Benachrichtigungen über Antwortaktualisierungen erhalten, aber ich habe meine Antwort mit einer noch einfacheren Methode aktualisiert :).
Solomon Rutzky

Antworten:

6

Ich weiß, dass dies ein bisschen brutal ist, aber was ist mit dem Deaktivieren und erneuten Aktivieren der CLR?

sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 0;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO
Max Vernon
quelle
2
Ein wichtiges Detail dieser Methode ist, dass sie bei Ausführung mit einer STANDBY-Datenbank (schreibgeschützt) funktioniert. Alle anderen Methoden, die ich ausprobiert habe, nicht. Ich brauchte dies, weil ein Update einer CLR-Assembly wie gewohnt per Protokollversand in einen STANDBY-Katalog übertragen wurde, die AppDomain jedoch nicht neu geladen wurde. Daher wurde der Code aus der alten Version der DLL etwa einen Tag lang ausgeführt.
Granger
@ Granger sehr interessant und gut zu wissen :). Ich würde dies jedoch als Fehler in SQL Server betrachten. Vielleicht möchten Sie dies über die Connect-Site melden
Solomon Rutzky
1
@srutzky - Danke für den Vorschlag; Ich gehe davon aus, dass sie den Bericht einfach als "Wird nicht repariert" schließen würden. Die Einstellung ist serverweit und nicht katalogübergreifend (genau wie "verschachtelte Trigger", "Dateistream-Zugriffsebene" usw.). Das ist ziemlich die Dose Würmer, die ich öffnen möchte.
Granger
@Granger (und Max): Mir war nicht klar, was ich sagte, ich dachte, es wäre ein Fehler. Ich habe nicht gesagt, dass das Zurücksetzen der Einstellung "CLR aktiviert", die das Entladen verursacht, ein Fehler ist. Ich sagte, dass die ALTER ASSEMBLYWeitergabe per Protokollversand, bei der die App-Domain nicht neu geladen (oder zumindest entladen) wurde, der Fehler war. In beiden Fällen habe ich eine noch einfachere Methode gefunden, die ich hier zu meiner Antwort hinzugefügt habe. Wenn Sie die Möglichkeit hätten, diese neue Methode zu testen, wäre das großartig, da ich sehr gespannt bin, ob sie in dem von Ihnen beschriebenen Protokollversand-Szenario funktioniert.
Solomon Rutzky
8

Es gibt eine elegantere Lösung, die nicht alle anderen Assemblys betrifft: Ändern Sie einfach das PERMISSION_SET einer der Assemblys in der App-Domäne (App-Domänen sind pro Benutzer).

ALTER ASSEMBLY [AssemblyName] WITH PERMISSION_SET = {1 of the 2 levels that 
                                                      this assembly is not current at}

Denken Sie daran, dass Sie PERMISSION_SET auf den ursprünglichen Wert zurücksetzen müssen. Außerdem müssen Sie auf eine Methode in der Assembly zugreifen, bevor Sie sie durch Ändern von PERMISSION_SET entladen. Das Ändern einer Assembly, die derzeit nicht in eine aktive App-Domäne geladen ist, jedoch eine andere Assembly hat, hat keine Auswirkungen auf die App-Domäne (App-Domänen sind pro DB, pro Benutzer und nicht pro Assembly).


UPDATE
Die oben beschriebene Methode ist der feinkörnigste Ansatz, bei dem nur diese eine App-Domäne entladen wird. Es ist jedoch erforderlich, dass die Baugruppe auf eine der beiden anderen Ebenen eingestellt werden kann. Für Baugruppen, die als gekennzeichnet gekennzeichnet sind, ist SAFEdies nur möglich

  • Die Datenbank ist auf TRUSTWORTHY ONoder eingestellt
  • Die Assembly ist signiert und ein Login, der auf einem asymmetrischen Schlüssel basiert, der selbst auf derselben Signatur wie die Assembly basiert, ist vorhanden und hat entweder EXTERNAL ACCESS ASSEMBLYdie UNSAFE ASSEMBLYBerechtigung oder die Berechtigung erhalten

In diesem Fall können Sie die TRUSTWORTHYEinstellung einfach ändern ONund dann sofort wieder OFFzurückkehren. Dadurch werden alle App-Domänen in dieser bestimmten Datenbank entladen :

ALTER DATABASE CURRENT SET TRUSTWORTHY ON;
ALTER DATABASE CURRENT SET TRUSTWORTHY OFF;

Wenn Sie ohnehin nur eine App-Domain in der Datenbank haben (und ich vermute, dass dies in 95% oder mehr der Fälle der Fall ist), haben beide hier beschriebenen Methoden den gleichen Nettoeffekt. In dieser Situation ALTER DATABASEscheint die Methode einfacher zu sein, da weder ein bestimmter Objektname angegeben werden muss noch das Original bekannt sein muss PERMISSION_SET.

AUCH, wenn Sie nur eine einzige App-Domäne haben, ist die ALTER DATABASEMethode einfacher, selbst wenn die Datenbank entweder bereits eingestellt ist TRUSTWORTHY ONoder Sie die Schlüsselbasis-Anmeldung mit der entsprechenden Berechtigung eingerichtet haben. Wenn Sie eine schlüsselbasierte Anmeldung verwenden, können Sie wie oben erwähnt TRUSTWORTHYauf ONund dann OFFerneut einstellen . Aber wenn Sie bereits TRUSTWORTHYgesetzt ON, dann umkehren es einfach und legen Sie es auf OFFund dann sofort wieder auf ON:

ALTER DATABASE CURRENT SET TRUSTWORTHY OFF;
ALTER DATABASE CURRENT SET TRUSTWORTHY ON;
Solomon Rutzky
quelle
1
Der aktualisierte Ansatz funktioniert in einem STANDBY-Datenbankkatalog (READ_ONLY). Mit SQL Server konnte ich die Einstellung "VERTRAUENSWERT" ändern und sie dann auf den vorherigen Stand zurücksetzen. Ich habe überprüft, ob die Änderung die Domain tatsächlich entladen hat, indem ich mir das Ergebnis von angesehen habe SELECT * FROM sys.dm_clr_appdomains;. Süss.
Granger