sql >> Database >  >> RDS >> Sqlserver

Msg 6522, Niveau 16 waarschuwing tijdens uitvoering van clr opgeslagen procedure

Er zijn verschillende problemen met deze code die moeten worden opgelost:

  1. Met betrekking tot de gestelde vraag, wanneer u een System.Security.SecurityException . krijgt fout, die verwijst naar de code die probeert buiten de database te komen, iets dat niet is toegestaan ​​in een SAFE bijeenkomst. Hoe u dit oplost, hangt af van wat u probeert te bereiken.

    • Als je probeert toegang te krijgen tot het bestandssysteem, uit het register te lezen, een omgevingsvariabele op te halen, toegang te krijgen tot het netwerk voor een niet-SQL Server-verbinding (bijv. http, ftp), enz., dan heeft de assembly een PERMISSION_SET van EXTERNAL_ACCESS . Om uw assembly in te stellen op iets anders dan SAFE , moet u ofwel:
      • Maak een certificaat of asymmetrische sleutel op basis van dezelfde sleutel die u hebt gebruikt om uw assembly te ondertekenen (d.w.z. geef het een sterke naam), maak een login op basis van dat certificaat of die asymmetrische sleutel en verleen vervolgens de EXTERNAL ACCESS ASSEMBLY toestemming voor die Login. Deze methode is zeer voorkeur boven de andere methode, namelijk:
      • Stel de database met de assembly in op TRUSTWORTHY ON . Deze methode mag alleen als laatste redmiddel worden gebruikt als het niet mogelijk is om de vergadering te ondertekenen. Of voor snelle testdoeleinden. Een database instellen op TRUSTWORTHY ON stelt uw instantie open voor potentiële beveiligingsrisico's en moet worden vermeden, zelfs als het sneller/gemakkelijker is dan de andere methode.
    • Als u probeert toegang te krijgen tot het SQL Server-exemplaar waarop u al bent aangemeld, hebt u de mogelijkheid om de in-process-verbinding van Context Connection = true; te gebruiken wat kan in een SAFE bijeenkomst. Dit is wat @Marc suggereerde in zijn antwoord. Hoewel er zeker voordelen zijn aan het gebruik van dit type verbinding, en hoewel de contextverbinding de juiste keuze was in dit specifieke scenario, is het te simplistisch en onjuist om te stellen dat u altijd gebruik dit type verbinding. Laten we eens kijken naar de positieve en negatieve aspecten van de Context Connection :

      • Positieven:
        • Kan worden gedaan in een SAFE montage.
        • Zeer lage of geen verbindingskosten aangezien het geen extra verbinding is.
        • Maakt deel uit van de huidige sessie, dus elke SQL die u uitvoert, heeft toegang tot sessiegebaseerde items zoals lokale tijdelijke tabellen en CONTEXT_INFO .
      • Minpunten:

        • Kan niet worden gebruikt als imitatie is ingeschakeld.
        • Kan alleen verbinding maken met de huidige SQL Server-instantie.
        • Als het wordt gebruikt in Functies (Scalar en Table-Valued) heeft het dezelfde beperkingen als T-SQL-functies (er zijn bijvoorbeeld geen neveneffecten toegestaan), behalve dat je alleen-lezen opgeslagen procedures kunt uitvoeren.
        • Tabel gewaardeerde functies mogen hun resultaten niet terug streamen als ze een resultatenset lezen.

        Al deze "negatieven" zijn toegestaan ​​bij gebruik van een reguliere / externe verbinding, zelfs als het gaat om dezelfde instantie van waaruit u deze code uitvoert.

  2. Als u verbinding maakt met de instantie van waaruit u deze code uitvoert en een externe / reguliere verbinding gebruikt, hoeft u de servernaam niet op te geven of zelfs localhost te gebruiken . De voorkeurssyntaxis is Server = (local) die gebruikmaakt van gedeeld geheugen, terwijl de andere soms TCP/IP gebruiken, wat niet zo efficiënt is.

  3. Gebruik Persist Security Info=True; niet, tenzij je een heel specifieke reden hebt om dit te doen.

  4. Het is een goede gewoonte om Dispose() van uw SqlCommand

  5. Het is efficiënter om de insertcommand.Parameters.Add() . aan te roepen net voor de for loop, en dan binnen de loop, stel de waarde eenvoudig in via firstname.Value = , wat u al doet, dus verplaats gewoon de insertcommand.Parameters.Add() regels tot net voor de for lijn.

  6. tel / @tel / listtelnumber zijn INT in plaats van VARCHAR / string . Telefoonnummers zijn, net als postcodes en burgerservicenummers (SSN's), niet cijfers, zelfs als ze lijken te zijn. INT kan leidende 0 niet opslaan s of iets als ex. om een ​​"extensie" aan te duiden.

  7. Dat gezegd hebbende, zelfs als al het bovenstaande is gecorrigeerd, is er nog steeds een enorm probleem met deze code dat moet worden aangepakt :dit is een nogal simplistische operatie om uit te voeren in gewone T-SQL, en dit doen in SQLCLR is te ingewikkeld, moeilijker en duurder om te onderhouden, en veel langzamer. Deze code voert 10.000 afzonderlijke transacties uit, terwijl het zo gemakkelijk zou kunnen worden gedaan als een enkele set-gebaseerde query (d.w.z. één transactie). Je zou je for . kunnen inpakken loop in een transactie die het zou versnellen, maar het zal altijd langzamer zijn dan de set-gebaseerde T-SQL-benadering, aangezien het nog steeds 10.000 afzonderlijke INSERT moet uitgeven verklaringen. U kunt eenvoudig willekeurig maken in T-SQL met behulp van NEWID() of CRYPT_GEN_RANDOM die werd geïntroduceerd in SQL Server 2008. (zie de UPDATE sectie hieronder)

Als je meer wilt weten over SQLCLR, bekijk dan de serie die ik schrijf voor SQL Server Central: Trap naar SQLCLR (gratis registratie vereist).

UPDATE

Hier is een pure T-SQL-methode om deze willekeurige gegevens te genereren, met behulp van de waarden uit de vraag. Het is gemakkelijk om nieuwe waarden toe te voegen aan een van de 4 tabelvariabelen (om het aantal mogelijke combinaties te vergroten), aangezien de query het randomisatiebereik dynamisch aanpast aan de gegevens in elke tabelvariabele (d.w.z. rijen 1 - n).

DECLARE @TelNumber TABLE (TelNumberID INT NOT NULL IDENTITY(1, 1),
                          Num VARCHAR(30) NOT NULL);
INSERT INTO @TelNumber (Num) VALUES ('1525407'), ('5423986'), ('1245398'), ('32657891'),
                                    ('123658974'), ('7896534'), ('12354698');

DECLARE @FirstName TABLE (FirstNameID INT NOT NULL IDENTITY(1, 1),
                          Name NVARCHAR(30) NOT NULL);
INSERT INTO @FirstName (Name) VALUES ('Babak'), ('Carolin'), ('Martin'), ('Marie'),
                  ('Susane'), ('Michail'), ('Ramona'), ('Ulf'), ('Dirk'), ('Sebastian');

DECLARE @LastName TABLE (LastNameID INT NOT NULL IDENTITY(1, 1),
                         Name NVARCHAR(30) NOT NULL);
INSERT INTO @LastName (Name) VALUES ('Bastan'), ('Krause'), ('Rosner'),
                  ('Gartenmeister'), ('Rentsch'), ('Benn'), ('Kycik'), ('Leuoth'),
                  ('Kamkar'), ('Kolaee');

DECLARE @Address TABLE (AddressID INT NOT NULL IDENTITY(1, 1),
                        Addr NVARCHAR(100) NOT NULL);
INSERT INTO @Address (Addr) VALUES ('Deutschlan Chemnitz Sonnenstraße 59'), (''),
  ('Deutschland Chemnitz Arthur-Strobel straße 124'),
  ('Deutschland Chemnitz Brückenstraße 3'),
  ('Iran Shiraz Chamran Blvd, Niayesh straße Nr.155'), (''),
  ('Deutschland Berlin Charlotenburg Pudbulesky Alleee 52'),
  ('United State of America Washington DC. Farbod Alle'), ('');

DECLARE @RowsToInsert INT = 10000;

;WITH rowcounts AS
(
  SELECT (SELECT COUNT(*) FROM @TelNumber) AS [TelNumberRows],
         (SELECT COUNT(*) FROM @FirstName) AS [FirstNameRows],
         (SELECT COUNT(*) FROM @LastName) AS [LastNameRows],
         (SELECT COUNT(*) FROM @Address) AS [AddressRows]
), nums AS
(
  SELECT TOP (@RowsToInsert)
         (CRYPT_GEN_RANDOM(1) % rc.TelNumberRows) + 1 AS [RandomTelNumberID],
         (CRYPT_GEN_RANDOM(1) % rc.FirstNameRows) + 1 AS [RandomFirstNameID],
         (CRYPT_GEN_RANDOM(1) % rc.LastNameRows) + 1 AS [RandomLastNameID],
         (CRYPT_GEN_RANDOM(1) % rc.AddressRows) + 1 AS [RandomAddressID]
  FROM   rowcounts rc
  CROSS JOIN msdb.sys.all_columns sac1
  CROSS JOIN msdb.sys.all_columns sac2
)
-- INSERT dbo.Unsprstb(Firstname, Lastname, Tel, Address)
SELECT fn.Name, ln.Name, tn.Num, ad.Addr
FROM   @FirstName fn
FULL JOIN nums
        ON nums.RandomFirstNameID = fn.FirstNameID
FULL JOIN @LastName ln
        ON ln.LastNameID = nums.RandomLastNameID
FULL JOIN @TelNumber tn
        ON tn.TelNumberID = nums.RandomTelNumberID
FULL JOIN @Address ad
        ON ad.AddressID = nums.RandomAddressID;

Opmerkingen:

  • De FULL JOIN s zijn nodig in plaats van INNER JOIN s om de volledige @RowsToInsert . te krijgen aantal rijen.
  • Dubbele rijen zijn mogelijk vanwege de aard van deze randomisatie EN ze niet uit te filteren met behulp van DISTINCT . Echter, DISTINCT kan niet worden gebruikt met de gegeven voorbeeldgegevens in de vraag, aangezien het aantal elementen in elke array / tabelvariabele slechts 6300 unieke combinaties biedt en het gevraagde aantal te genereren rijen 10.000 is. Als er meer waarden aan de tabelvariabelen worden toegevoegd, zodat het totaal aantal mogelijke unieke combinaties boven het gevraagde aantal rijen komt, dan wordt ofwel de DISTINCT trefwoord kan worden toegevoegd aan de nums CTE, of de zoekopdracht kan worden geherstructureerd tot eenvoudig CROSS JOIN alle tabelvariabelen, inclusief een ROW_COUNT() veld, en pak de TOP(n) met behulp van ORDER BY NEWID() .
  • De INSERT wordt becommentarieerd, zodat het gemakkelijker is om te zien dat de bovenstaande zoekopdracht het gewenste resultaat oplevert. Uncommentaar de INSERT om de query de eigenlijke DML-bewerking te laten uitvoeren.


  1. db.create_all() 'NoneType'-object heeft geen kenmerk 'drivername'

  2. Meer dan 60 seconden of minuten in MySQL-importbestand

  3. Verbinding maken met Mysql met Slick 3.0 - Geen gebruikersnaam, geen wachtwoord en nep-stuurprogramma is geen fout

  4. MySQL:Waarom slaat mijn INSERT-instructie 56 nummers over bij het automatisch verhogen van de id?