Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Msg 6522, ostrzeżenie o poziomie 16 podczas wykonywania procedury składowanej clr

W tym kodzie pojawia się kilka problemów, które należy rozwiązać:

  1. Jeśli chodzi o zadane pytanie, gdy pojawi się System.Security.SecurityException błąd, który odnosi się do kodu próbującego sięgnąć poza bazę danych, coś, co nie jest dozwolone w BEZPIECZNY montaż. Sposób, w jaki to naprawisz, zależy od tego, co próbujesz osiągnąć.

    • Jeśli próbujesz uzyskać dostęp do systemu plików, odczytać z rejestru, uzyskać zmienną środowiskową, uzyskać dostęp do sieci dla połączenia innego niż SQL Server (np. http, ftp) itp., wtedy zespół potrzebuje PERMISSION_SET z EXTERNAL_ACCESS . Aby ustawić swój zespół na cokolwiek innego niż BEZPIECZNY , musisz:
      • Utwórz certyfikat lub klucz asymetryczny na podstawie tego samego klucza, którego użyłeś do podpisania swojego zestawu (tj. nadaj mu silną nazwę), utwórz login oparty na tym certyfikacie lub kluczu asymetrycznym, a następnie przyznaj DOSTĘP ZEWNĘTRZNY MONTAŻ uprawnienia do tego logowania. Ta metoda jest wspaniale preferowana w stosunku do innej metody, którą jest:
      • Ustaw bazę danych zawierającą zestaw na TRUSTWORTHY ON . Ta metoda powinna być stosowana tylko w ostateczności, jeśli nie ma możliwości podpisania zgromadzenia. Lub do szybkiego testowania. Ustawianie bazy danych na ZAUFANIE NA otwiera Twoją instancję na potencjalne zagrożenia bezpieczeństwa i należy tego unikać, nawet jeśli jest szybsza / łatwiejsza niż druga metoda.
    • Jeśli próbujesz uzyskać dostęp do instancji SQL Server, do której jesteś już zalogowany, możesz użyć połączenia w procesie Context Connection =true; co można zrobić w SAFE montaż. To właśnie zasugerował @Marc w swojej odpowiedzi. Chociaż korzystanie z tego typu połączenia zdecydowanie przynosi korzyści i chociaż połączenie kontekstowe było właściwym wyborem w tym konkretnym scenariuszu, stwierdzenie, że należy zawsze jest zbyt uproszczone i nieprawidłowe użyj tego typu połączenia. Przyjrzyjmy się pozytywnym i negatywnym aspektom Powiązania kontekstu :

      • Pozytywy:
        • Można to zrobić w BEZPIECZNYM montaż.
        • Bardzo niski, jeśli w ogóle, koszt połączenia, ponieważ nie jest to dodatkowe połączenie.
        • Jest częścią bieżącej sesji, więc każdy wykonywany kod SQL ma dostęp do elementów sesji, takich jak lokalne tabele tymczasowe i CONTEXT_INFO .
      • Negatywy:

        • Nie można użyć, jeśli włączona jest personifikacja.
        • Może łączyć się tylko z bieżącą instancją SQL Server.
        • Gdy jest używany w funkcjach (skalarnych i z wartościami tabelarycznymi), ma wszystkie te same ograniczenia, które mają funkcje T-SQL (np. nie są dozwolone żadne operacje uboczne), z wyjątkiem tego, że można wykonywać procedury przechowywane tylko do odczytu.
        • Funkcje o wartościach tabelarycznych nie mogą przesyłać strumieniowo swoich wyników z powrotem, jeśli odczytują zestaw wyników.

        Wszystkie te „negatywy” są dozwolone podczas korzystania ze zwykłego/zewnętrznego połączenia, nawet jeśli jest to ta sama instancja, z której wykonujesz ten kod.

  2. Jeśli łączysz się z instancją, z której wykonujesz ten kod i używasz połączenia zewnętrznego / zwykłego, nie musisz określać nazwy serwera ani nawet używać localhost . Preferowana składnia to Server =(local) który używa pamięci współdzielonej, podczas gdy inne mogą czasami używać protokołu TCP/IP, który nie jest tak wydajny.

  3. Jeśli nie masz bardzo konkretnego powodu, nie używaj Persist Security Info=True;

  4. Dobrą praktyką jest Dispose() Twojego SqlCommand

  5. Bardziej wydajne jest wywołanie insertcommand.Parameters.Add() tuż przed for pętli, a następnie wewnątrz pętli, po prostu ustaw wartość za pomocą firstname.Value = , co już robisz, więc po prostu przenieś insertcommand.Parameters.Add() wiersze tuż przed for linia.

  6. tel / @tel / numer listyINT zamiast VARCHAR / ciąg . Numery telefonów, podobnie jak kody pocztowe i numery ubezpieczenia społecznego (SSN), nie numery, nawet jeśli tak się wydaje. INT nie można przechowywać wiodącego 0 s lub coś takiego jak np. oznaczające „rozszerzenie”.

  7. Biorąc to wszystko pod uwagę, nawet jeśli wszystkie powyższe kwestie zostaną poprawione, nadal istnieje ogromny problem z tym kodem, którym należy się zająć :jest to dość uproszczona operacja do wykonania w prostym języku T-SQL, a wykonanie tego w SQLCLR jest nadmiernie skomplikowane, trudniejsze i bardziej kosztowne w utrzymaniu oraz znacznie wolniejsze. Ten kod wykonuje 10 000 oddzielnych transakcji, podczas gdy można go tak łatwo wykonać jako pojedyncze zapytanie oparte na zestawie (tj. Jedna transakcja). Możesz zawinąć swój dla pętla w transakcji, która by ją przyspieszyła, ale nadal będzie wolniejsza niż podejście T-SQL oparte na zbiorach, ponieważ nadal wymaga wydania 10 000 oddzielnych INSERT sprawozdania. Możesz łatwo losować w T-SQL za pomocą NEWID() lub CRYPT_GEN_RANDOM który został wprowadzony w SQL Server 2008. (zobacz AKTUALIZACJA sekcja poniżej)

Jeśli chcesz dowiedzieć się więcej o SQLCLR, zapoznaj się z serią, którą piszę dla SQL Server Central: Schody do SQLCLR (wymagana bezpłatna rejestracja).

AKTUALIZUJ

Oto czysta metoda T-SQL generowania tych losowych danych przy użyciu wartości z pytania. Łatwo jest dodać nowe wartości do dowolnej z 4 zmiennych tabeli (aby zwiększyć liczbę możliwych kombinacji), ponieważ zapytanie dynamicznie dostosowuje zakres randomizacji, aby dopasować dowolne dane w każdej zmiennej tabeli (tj. wiersze 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;

Uwagi:

  • PEŁNE DOŁĄCZENIE s są potrzebne zamiast INNER JOIN s, aby uzyskać cały @RowsToInsert liczba wierszy.
  • Zduplikowane wiersze są możliwe ze względu na samą naturę tej randomizacji ORAZ nie odfiltrowywanie ich za pomocą DISTINCT . Jednak DISTINCT nie może być użyty z podanymi przykładowymi danymi w pytaniu, ponieważ liczba elementów w każdej zmiennej tablicy / tabeli zapewnia tylko 6300 unikalnych kombinacji, a żądana liczba wierszy do wygenerowania to 10 000. Jeśli do zmiennych tabeli zostanie dodanych więcej wartości, tak że łączna liczba możliwych unikalnych kombinacji wzrośnie powyżej żądanej liczby wierszy, wtedy albo DISTINCT słowo kluczowe można dodać do nums CTE lub zapytanie może zostać zrestrukturyzowane, aby po prostu CROSS JOIN wszystkie zmienne tabeli, zawierają ROW_COUNT() i chwyć TOP(n) używając ORDER BY NEWID() .
  • Karta WSTAW jest wykomentowany, więc łatwiej jest zauważyć, że powyższe zapytanie daje pożądany wynik. Po prostu odkomentuj INSERT aby zapytanie wykonało rzeczywistą operację DML.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nie można dodać warunku w części FOR XML

  2. Instalacja SQL Server 2017 krok po kroku -2

  3. Dostaję komunikat Podjęto próbę załadowania programu z niepoprawnym błędem formatu w projekcie replikacji programu SQL Server

  4. Sortowanie zawsze zwraca ten sam wynik

  5. Kopia zapasowa na poziomie tabeli