sql >> Base de Datos >  >> RDS >> Sqlserver

Mensaje 6522, advertencia de nivel 16 durante la ejecución del procedimiento almacenado clr

Hay varios problemas en este código que deben abordarse:

  1. Con respecto a la pregunta indicada, cuando recibe una System.Security.SecurityException error, que se refiere al código que intenta llegar fuera de la base de datos, algo que no está permitido en un SAFE asamblea. La forma en que solucione esto depende de lo que intente lograr.

    • Si está tratando de acceder al sistema de archivos, leer del registro, obtener una variable de entorno, acceder a la red para una conexión que no sea de SQL Server (por ejemplo, http, ftp), etc., entonces el ensamblado necesita un PERMISSION_SET de EXTERNAL_ACCESS . Para configurar su ensamblaje en algo que no sea SAFE , debe:
      • Cree un certificado o clave asimétrica basado en la misma clave que usó para firmar su ensamblaje (es decir, asígnele un nombre seguro), cree un inicio de sesión basado en ese certificado o clave asimétrica y luego otorgue el EXTERNAL ACCESS ASSEMBLY permiso para ese inicio de sesión. Este método es muy preferido sobre el otro método, que es:
      • Establecer la base de datos que contiene el ensamblado en TRUSTWORTHY ON . Este método solo debe usarse como último recurso si no es posible firmar el ensamblaje. O para fines de prueba rápida. Establecer una base de datos en TRUSTWORTHY ON abre su instancia a posibles amenazas de seguridad y debe evitarse, incluso si es más rápido o más fácil que el otro método.
    • Si está intentando acceder a la instancia de SQL Server en la que ya ha iniciado sesión, tiene la opción de utilizar la conexión en proceso de Context Connection = true; que se puede hacer en un SAFE asamblea. Esto es lo que sugirió @Marc en su respuesta. Si bien definitivamente hay beneficios en el uso de este tipo de conexión, y aunque la Conexión de contexto fue la opción adecuada en este escenario en particular, es demasiado simplista e incorrecto afirmar que debe siempre utilizar este tipo de conexión. Veamos los aspectos positivos y negativos de la Conexión de contexto :

      • Positivos:
        • Se puede hacer en un SAFE montaje.
        • Sobrecarga de conexión muy baja, si la hay, ya que no es una conexión adicional.
        • Es parte de la sesión actual, por lo que cualquier SQL que ejecute tenga acceso a elementos basados ​​en la sesión, como tablas temporales locales y CONTEXT_INFO .
      • Negativos:

        • No se puede usar si se ha habilitado la suplantación de identidad.
        • Solo se puede conectar a la instancia actual de SQL Server.
        • Cuando se usa en funciones (escalares y con valores de tabla), tiene todas las mismas restricciones que tienen las funciones de T-SQL (por ejemplo, no se permiten operaciones con efectos secundarios), excepto que puede ejecutar procedimientos almacenados de solo lectura.
        • Las funciones con valores de tabla no pueden transmitir sus resultados si leen un conjunto de resultados.

        Todos estos "negativos" están permitidos cuando se utiliza una conexión normal/externa, incluso si se trata de la misma instancia desde la que está ejecutando este código.

  2. Si se está conectando a la instancia desde la que está ejecutando este código y usa una conexión externa/regular, entonces no es necesario especificar el nombre del servidor o incluso usar localhost . La sintaxis preferida es Server = (local) que usa memoria compartida, mientras que los demás a veces pueden usar TCP/IP, que no es tan eficiente.

  3. A menos que tenga una razón muy específica para hacerlo, no use Persist Security Info=True;

  4. Es una buena práctica Dispose() de su SqlCommand

  5. Es más eficiente llamar a insertcommand.Parameters.Add() justo antes del for bucle, y luego dentro del bucle, simplemente establezca el valor a través de firstname.Value = , lo que ya está haciendo, así que simplemente mueva insertcommand.Parameters.Add() líneas justo antes del for línea.

  6. tel / @tel / listtelnumber son INT en lugar de VARCHAR / string . Los números de teléfono, al igual que los códigos postales y los Números de Seguro Social (SSN), no números, incluso si lo parecen. INT no se puede almacenar el 0 inicial s o algo así como ex. para significar una "extensión".

  7. Habiendo dicho todo eso, incluso si se corrige todo lo anterior, todavía hay un gran problema con este código que debe abordarse :esta es una operación bastante simple para realizar en T-SQL directo, y hacerlo en SQLCLR es demasiado complicado, más difícil y más costoso de mantener, y mucho más lento. Este código está realizando 10,000 transacciones separadas, mientras que podría realizarse fácilmente como una única consulta basada en conjuntos (es decir, una transacción). Podrías envolver tu for bucle en una transacción que la aceleraría, pero siempre será más lento que el enfoque T-SQL basado en conjuntos, ya que aún necesita emitir 10,000 INSERT separados declaraciones. Puede aleatorizar fácilmente en T-SQL usando NEWID() o CRYPT_GEN_RANDOM que se introdujo en SQL Server 2008. (consulte la ACTUALIZACIÓN sección a continuación)

Si desea obtener más información sobre SQLCLR, consulte la serie que estoy escribiendo para SQL Server Central: Escalera a SQLCLR (se requiere registro gratuito).

ACTUALIZAR

Aquí hay un método T-SQL puro para generar estos datos aleatorios, usando los valores de la Pregunta. Es fácil agregar nuevos valores a cualquiera de las 4 variables de la tabla (para aumentar el número de combinaciones posibles) ya que la consulta ajusta dinámicamente el rango de aleatorización para adaptarse a cualquier dato que haya en cada variable de la tabla (es decir, filas 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;

Notas:

  • La FULL JOIN se necesitan s en lugar de INNER JOIN s para obtener el @RowsToInsert completo cantidad de filas.
  • Las filas duplicadas son posibles debido a la naturaleza misma de esta aleatorización Y no filtrarlas usando DISTINCT . Sin embargo, DISTINCT no se puede usar con los datos de muestra proporcionados en la pregunta, ya que la cantidad de elementos en cada matriz/variable de tabla proporciona solo 6300 combinaciones únicas y la cantidad solicitada de filas para generar es 10,000. Si se agregan más valores a las variables de la tabla de modo que el total de combinaciones únicas posibles supere el número solicitado de filas, entonces DISTINCT la palabra clave se puede agregar a los nums CTE, o la consulta se puede reestructurar para simplemente CROSS JOIN toda la variable de la tabla, incluya un ROW_COUNT() y toma el TOP(n) usando ORDER BY NEWID() .
  • El INSERT está comentado para que sea más fácil ver que la consulta anterior produce el resultado deseado. Simplemente descomente el INSERT para que la consulta realice la operación DML real.