2016-01-10 4 views
2

У меня есть хранимая процедура SQL CLR, которая анализирует строку TLVBER, эта процедура CLR вызывается каждый раз, когда команда отправляется в БД, имеется 6 команд.Выполнение хранимых процедур CLR из SQL Server

Команды 6 представляют собой одну транзакцию.

В каждой команде принимают строку TLVBER, я разбираю строку в тегах с их значением, затем вставляю ее или обновляю в соответствующем столбце/таблице. Важно, чтобы этот тег существовал в БД, я проверяю его с помощью запроса.

Чтобы узнать, в какой колонке/таблице тег вставлен или обновлен, у меня есть таблица в БД, где я храню id_tag, таблицу и столбец.

Вот проблема:

Я не знаю, что это лучший вариант, чтобы сделать, потому что я закодирован весь процесс в CLR, я сделал много запросов и вставляет & обновления.

Одна единственная проблема, например, заключается в том, что я должен создать временную таблицу, и я прочитал, что это не рекомендуется, поэтому я решаю это с помощью CLR, потому что вы можете использовать ArrayList; в общем, проще с кодом C#, чем с T-SQL.

С другой стороны I've мысль вставить все теги в одной таблице, и ссылки эти метки с идентификатором, потому что если я хранить все теги в одном столе, я буду хранить теги все разные КОМАНДЫ, отправленные в базу данных.

Это критическое время обработки, поскольку в минуту будет совершаться тысячи транзакций.

В CLR мне приходится запрашивать данные из БД (могут ли запросы скомпрометировать время, необходимое для CLR?).

Следующая проблема заключается в конце разбора TLVBER, поскольку мне нужно объединить результаты анализа и сравнить каждый тег (каждый тег итерации его с помощью ArrayList) разобрать и запросить таблицу/столбец, где вставлен или обновлен. Я думал, что было бы лучше построить запросы, вернуть его как таблицу в T-SQL, чтобы выполнение было быстрее в T-SQL, чем в CLR.

В любом случае мне нужно сделать много запросов к БД для получения информации, так есть способ отправить таблицы в CLR SP ?; чтобы избежать запросов из CLR, вместо этого было бы лучше запросить необходимые данные в T-SQL и отправить его в CLR, чтобы этот процесс обрабатывал данные и не вступал в какое-либо взаимодействие с БД (без соединений, которые генерируют задержки, только обработка данных).

Ну код ниже покажет вам, как я призываю CLR от T-SQL, то я покажу вам петлю, где я делаю запросы и вставляет & обновления

EXEC SP_CLR_PARSEATLVBER @TLV= '00102001010010010100100201007F010101', 
        @[email protected] OUTPUT, 
        @CMD='OPN' 

while (cursor <= total) 
     { 
      Stag = ""; 
      // -- * ******************EXTRAE TAG******************* 
      tag = TLV.ToString().ToCharArray(cursor, 4); 
      foreach (char c in tag) 
       Stag = Stag + c; 
      Stag = "0x" + Stag; 
      InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " '" + "TAG:" + Stag + "'," + 
            " '128'," + 
            " SYSDATETIME()" + 
            ")"; 
      InsertaLog.ExecuteNonQuery(); 
      SeleccionaTag.CommandText = "SELECT id_tag FROM dbo.tags where dbo.tags.id_tag = '" + Stag + "'"; 
      SeleccionaTag.Connection = conn; 
      reader = SeleccionaTag.ExecuteReader(); 
      int vacio = 0; 
      String id_tag = ""; 
      while (reader.Read()) 
      { 
       vacio++; 
       id_tag = reader.GetSqlString(0).ToString(); 
      } 
      reader.Close(); 
      if (vacio == 0) 
      { 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'ID_TAG NO SE ENCUENTRA'," + 
            " '137'," + 
            " SYSDATETIME()" + 
            ")"; 
       InsertaLog.ExecuteNonQuery(); 
      } 
      { 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
             " ('PARSEATLVBER', " + 
             " '" + "Vacio:" + id_tag + "'," + 
             " '137'," + 
             " SYSDATETIME()" + 
             ")"; 
       InsertaLog.ExecuteNonQuery(); 
      }    


      //-- ///////////////////////////////////// 



      //  --*******************AVANCE EN LA CADENA******************* 
      cursor = cursor + 4; 
      InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'Cursor despues de extraer tag(" + Stag + "): " + cursor.ToString() + "'," + 
            " '137'," + 
            " SYSDATETIME()" + 
            ")"; 
      InsertaLog.ExecuteNonQuery(); 
      //  -- ///////////////////////////////////// 
      // --*******************EXTRAE TAMAÑO EN BYTES DEL TAG EXTRAIDO ******************* 
      length = TLV.ToString().ToCharArray(cursor, 2); 
      Slength = ""; 
      foreach (char c in length) 
       Slength = Slength + c; 
      InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'TAMAÑO DE TAG:" + Slength + "'," + 
            " '209'," + 
            " SYSDATETIME()" + 
            ")"; 
      Int32.TryParse(Slength, NumberStyles.HexNumber, 
           new CultureInfo("en-US"), out varlength); 
      InsertaLog.ExecuteNonQuery(); 
      InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'TAMAÑO DE TAG(INT):" + varlength.ToString() + "'," + 
            " '218'," + 
            " SYSDATETIME()" + 
            ")"; 
      InsertaLog.ExecuteNonQuery(); 
      Slength = ""; 
      if ((varlength) > 127) 
      { 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            "'TAG SUPERA LONGITUD'," + 
            " '227'," + 
            " SYSDATETIME()" + 
            ")"; 
       InsertaLog.ExecuteNonQuery(); 
       varlength = 0; 
       // --*******************AVANCE EN LA CADENA******************* 
       cursor = cursor + 2; 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
             " ('PARSEATLVBER', " + 
             " 'Cursor despues de extraer tamaño de TAG(" + tag + "):" +cursor+ "'," + 
             " '237'," + 
             " SYSDATETIME()" + 
             ")"; 
       InsertaLog.ExecuteNonQuery(); 
       // -- ///////////////////////////////////// 
       TotalBytes = varlength - 128; 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'Total de Bytes Asignados de la longitud del TAG(" + tag + "):" + TotalBytes+"',"+ 
            " '246'," + 
            " SYSDATETIME()" + 
            ")"; 
       InsertaLog.ExecuteNonQuery(); 
       length = TLV.ToString().ToCharArray(cursor, 2); 
       foreach (char c in length) 
        Slength = Slength + c; 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'TAMAÑO DE TAG:" + Slength + "'," + 
            " '257'," + 
            " SYSDATETIME()" + 
            ")"; 
       InsertaLog.ExecuteNonQuery(); 
       Int32.TryParse(Slength, NumberStyles.HexNumber, 
           new CultureInfo("en-US"), out varlength); 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
             " ('PARSEATLVBER', " + 
             " 'TAMAÑO DE TAG(INT):" + varlength.ToString() + "'," + 
             " '266'," + 
             " SYSDATETIME()" + 
             ")"; 
       InsertaLog.ExecuteNonQuery(); 
       varlength = varlength * 2; 
       //--*******************AVANCE EN LA CADENA******************* 
       cursor = cursor + (TotalBytes * 2); 
       // -- ///////////////////////////////////// 
      } 
      else 
      { 
       length = TLV.ToString().ToCharArray(cursor, 2); 
       Slength = ""; 
       foreach (char c in length) 
        Slength = Slength + c; 
       Int32.TryParse(Slength, NumberStyles.HexNumber, 
           new CultureInfo("en-US"), out varlength); 
       //--*******************AVANCE EN LA CADENA******************* 
       cursor = cursor + 2; 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'Slength:" + Slength + "'," + 
            " '286'," + 
            " SYSDATETIME()" + 
            ")"; 
       InsertaLog.ExecuteNonQuery(); 
       InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'TAMAÑO DE TAG(INT):" + varlength.ToString() + "'," + 
            " '294'," + 
            " SYSDATETIME()" + 
            ")"; 
       InsertaLog.ExecuteNonQuery(); 
       // -- ///////////////////////////////////// 
      } 
      //-- ///////////////////////////////////// 
      //-- * ******************EXTRAE VALOR DE TAG EXTRAIDO ******************* 
      value = TLV.ToString().ToCharArray(cursor, varlength); 
      foreach (char c in value) 
       Svalue = Svalue + c; 
      SeleccionaTipoDato.CommandText = "SELECT dbo.TAGS.tipodato" + 
              " FROM dbo.TAGS" + 
              " WHERE dbo.TAGS.id_tag = '" + tag + "'"; 
      SeleccionaTipoDato.Connection = conn; 
      reader = SeleccionaTipoDato.ExecuteReader(); 
      while (reader.Read()) 
      { 
       tipoDato = reader.GetSqlString(0).ToString(); 
      } 
      InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
            " ('PARSEATLVBER', " + 
            " 'TipoDato:" + tipoDato.ToString() + "'," + 
            " '294'," + 
            " SYSDATETIME()" + 
            ")"; 
      InsertaLog.ExecuteNonQuery(); 
      reader.Close(); 
      if (tipoDato.Equals("ASCII")) 
      { 
       Convertidor C = new Convertidor(); 
       valorParseadoASCII=C.ValueToASCII(Svalue); 
      } 
      cursor = cursor + varlength; 
      //-- ///////////////////////////////////// 
      //-- ******************* Tabla para agregar tags con su respectivo valor ******************* 
      Tupla.Add(Stag); 
      Tupla.Add(Svalue); 
      if(tag.Equals("0x2005")) 
       TID = Svalue; 
      if(tag.Equals("0x1003")) 
       MID = Svalue; 
      if (tag.Equals("0xE001")) 
       xid = Convert.ToInt64(Svalue); 
      CMD.Add(Tupla); 
      InsertaLog.CommandText = "INSERT INTO DBO.LOGDB values " + 
             " ('PARSEATLVBER', " + 
             " 'Tupla Agregada: (" + Tupla[0]+","+Tupla[1] + ")'," + 
             " '320'," + 
             " SYSDATETIME()" + 
             ")"; 
      InsertaLog.ExecuteNonQuery(); 
      Tupla.Clear(); 
      Svalue = ""; 
      Slength = ""; 
      Stag = ""; 
      //-- ///////////////////////////////////// 
    } 
     // INSERCION DE CAMPO LLAVE 
     if (cmd.Equals("OPN")) 
     { 
      SeleccionaNuevaLLave.CommandText = "SELECT NEXT VALUE FOR dbo.llave"; 
      reader = SeleccionaNuevaLLave.ExecuteReader(); 
      while (reader.Read()) 
        SecuenciaLlave = Convert.ToInt64(reader.GetSqlString(0)); 
      reader = SeleccionaNuevaLLave.ExecuteReader(); 
      SeleccionaNuevaTransId.CommandText = "SELECT NEXT VALUE FOR dbo.transid"; 
      while (reader.Read()) 
       SecuenciaTransid = Convert.ToInt64(reader.GetSqlString(0)); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO dbo.transaccion"+ 
                " values (xid,trans_id,mid,tid)" + 
                " ("+SecuenciaLlave + "," + 
                 SecuenciaTransid + "," + 
                 MID    + "," + 
                 TID    + 
                ")"; 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.AMT (xid) values (" + SecuenciaLlave +")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.CRD (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.DMO (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.HST (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.MRC (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.PRO (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.RCV (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
      InsertaNuevaTransaccion.CommandText = "INSERT INTO DBO.SND (xid) values (" + SecuenciaLlave + ")"; InsertaNuevaTransaccion.ExecuteNonQuery(); 
     } 
     else 
     { 
      SecuenciaLlave = xid; 
     } 

     int j = 0; 
     String tabla,columna; 
     foreach (ArrayList A in CMD) 
     { 
      SeleccionaTipoDato.CommandText = "SELECT dbo.TAGS.tabla,"+ 
                " dbo.TAGS.columna" + 
              " FROM dbo.TAGS" + 
              " WHERE dbo.TAGS.id_tag = '" + A[0].ToString() + "'"; 
      reader = SeleccionaTipoDato.ExecuteReader(); 
      while (reader.Read()) 
      { 
       tabla = reader.GetSqlString(0).ToString(); 
       columna = reader.GetSqlString(1).ToString(); 
       ActualizaTabla.CommandText = "UPDATE " 
              +tabla+ 
              " SET " 
              +columna+"='"+A[1]+"'"+ 
              " where "+tabla+".xid="+SecuenciaLlave; 
       ActualizaTabla.ExecuteNonQuery(); 
      } 
     } 

Игнорируйте вставки в DBO. LOGDB, они предназначены для целей отладки, другие запросов & Вставка и обновления являются критическим процессом.

Вопрос в том, как я могу выполнять обработку данных в CLR, передавая их таблицы и анализируя данные, а только строить запросы и отправлять их в T-SQL, чтобы это выполнялось ?, или нет никаких проблем при задержке вызова запросов & вставки & обновления.

Считайте, что эта процедура CLR будет называться много, много раз в минуту.

+0

CLR использует память за пределами установленного предела настроек памяти, поэтому я рекомендую проверить запрос на тестовом сервере с максимальным входом и увидеть CLR-память. Производительность clr может быть проверена путем просмотра использования памяти компонентов clr через (выберите * из sys.dm_os_memory_clerks, где type = 'memoryclerk_clr'.Чтобы передать datatables в clr, создайте тип таблицы, определенный пользователем, в sql – TheGameiswar

+0

. Другое дело, что использование CLR означает, что запрос будет выполняться последовательно. См. http: // blogs .technet.com/b/italian_premier_center_for_sql_server/archive/2013/09/04/sqlclr-functions-and-parallelelism.aspx. Если возможно, инкапсулируйте логику в функцию (возможно, clr), которая не нуждается в доступе к данным, и выполните rest в T-SQL. –

+0

@TheGameiswar re «Чтобы передать данные в clr, создайте определенный тип таблицы в sql»: это, к сожалению, неправда. Объекты SQLCLR не могут принимать TVP. Если вы хотите передать в таблицу, вы можете либо передать строку с разделителями, которая будет разбираться (например, строка запроса HTTP), либо вы можете хранить данные в локальной временной таблице и передавать имя этой таблицы, а из нее - SELECT в объекте SQLCLR. –

ответ

2

Одна единственная проблема, например, в том, что я должен сделать временную таблицу, и я читал, что не рекомендую, так вот почему я решить эту проблему с CLR

Где вы читали, что вы не следует создавать временные таблицы? И почему вы доверяете этой информации? Были ли предоставлены доказательства? Временные таблицы должны быть точными. И если не будет много строк, вы даже можете попробовать использовать переменные таблицы.

Из того, что я могу видеть из кода (хотя это трудно сказать, так как кажется, что большая часть этого кода отладки, что отладка вещи должны быть действительно хранимой процедуры вместо динамического SQL и переехал в отдельный метод, так что это всего лишь одна строка каждый раз в этом коде), здесь действительно не так много делается, что требует использования SQLCLR. Наиболее применимой операцией является первоначальное расщепление строки на куски, что - это что-то, что SQLCLR может сделать довольно эффективно. Похоже, каждый цикл использует 8 символов из исходной строки, так что написать простой SQLCLR TVF с в виду следующее:

  1. Если входная строка никогда не будет больше, чем 4000 символов, обязательно используйте NVARCHAR(4000) через [SqlFacet(MaxSize = 4000)] SqlString TLV.
  2. Создайте структуру из трех строк, и для каждого набора из 8 символов возвращайте 4, 2 и 2 в эти 3 поля.
  3. Используйте yield return theObject;, чтобы поток из результатов
  4. обязательно укажите IsDeterministic = true; в атрибуте SqlFunction()
  5. убедитесь, что вы не делать каких-либо доступа к данным (но нет необходимости отмечать DataAccessKind.None так, что по умолчанию).
  6. убедитесь, что держать Ассамблею помечена как WITH PERMISSION_SET = SAFE

Эти заключительные 3 пунктов может позволить SQLCLR ТВФ, чтобы иметь возможность участвовать в параллельных планах (я знаю, что он работает со скалярными функциями, не уверен TVFs) ,

Некоторых заметки о коде # C и процессе в целом:

  • Почему продолжают называть TLV.ToString().ToCharArray()? Почему бы просто не создать char[] в начале и назначить TLV.ToString().ToCharArray()? Тогда вам не нужно повторять эту операцию столько раз.
  • SqlDataReader - одноразовый объект, но вы только когда-либо закрываете их.
  • Если этот код будет работать так часто, вы можете подумать об отладке, поскольку он выполняет много однострочных операторов DML, что является большим количеством дополнительных транзакций, замедляющих этот процесс.
  • Возможно, вы захотите реструктурировать это, чтобы быть более основанным на наборе, и не делать так много операций на каждый патрон строки .
  • Действительно ли вы храните шестнадцатеричные значения в виде строк (например, SeleccionaTag.CommandText = "SELECT id_tag FROM dbo.tags where dbo.tags.id_tag = '" + Stag + "'";)? Что-то не похоже на это.
  • Если вы хотите передать таблицу/массив в хранимую процедуру SQLCLR, вы можете либо передать строку с разделителями в pars, либо сохранить значения в локальных временных таблицах и передать имена таблиц для этих временных таблиц.
Смежные вопросы