HttpWebRequest在SQLCLR中第一次运行缓慢

时间:2009-08-18 08:47:53

标签: sql-server-2005 sqlclr

在CLR存储过程中进行HttpWebRequest时(根据下面的代码),在(重新)启动Sql Server之后或在给定(但不确定)的时间段之后的第一次调用等待相当长的时间GetResponse()方法调用的时间。

有没有办法解决这个问题,不涉及“黑客”,例如每隔几分钟运行一次Sql Server Agent作业,以确保代理进行第一次“慢速”调用,而不是“真正的“生产代码?

function SqlString MakeWebRequest(string address, string parameters, int connectTO)
{
  SqlString returnData;
  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString())); 
  request.Timeout = (int)connectTO;
  request.Method = "GET";
  using (WebResponse response = request.GetResponse())
  {
    using (Stream responseStream = response.GetResponseStream())
    {
      using (StreamReader reader = new StreamReader(responseStream))
      {
        SqlString responseFromServer = reader.ReadToEnd();
        returnData = responseFromServer;
      }
    }
  }
  response.Close();

  return returnData;
}

(为简洁起见,已删除错误处理和其他非关键代码)


另见this Sql Server forums thread

6 个答案:

答案 0 :(得分:10)

这对我来说首先使用HttpWebRequest是一个问题。这是由于该类正在寻找使用的代理。如果您将对象的Proxy值设置为null / Nothing,则会直接拉链。

答案 1 :(得分:4)

在我看来,就像代码签名验证一样。 MS发送的系统dll都已签名,SQL在加载时验证签名。显然证书撤销列表已过期,证书验证引擎超时检索新列表。我在Fix slow application startup due to code sign validation之前发布过有关此问题的博文,此问题也在此Technet文章中进行了描述:Certificate Revocation and Status Checking

该解决方案非常神秘,涉及密钥的注册表编辑:HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config

  • ChainUrlRetrievalTimeoutMilliseconds 这是每个单独的CRL检查调用超时。如果为0或不存在,则使用默认值15秒。将此超时更改为合理的值,如200毫秒。
  • ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds 这是聚合CRL检索超时。如果设置为0或不存在,则使用默认值20秒。将此超时更改为500毫秒的值。

Microsoft signed assemblies还有一个更具体的解决方案(这来自Biztalk文档,但适用于任何程序集负载):

  

手动加载Microsoft证书   撤销清单

     

启动.NET应用程序时,   .NET Framework将尝试   下载证书撤销   任何已签名程序集的列表(CRL)。如果   你的系统没有直接的   访问互联网,或者是   限制访问   Microsoft.com域名,这可能会延迟   启动BizTalk Server。避免   你应用程序启动时的这种延迟   可以使用以下步骤   手动下载并安装代码   签署证书撤销列表   在你的系统上。

     
      
  1. 从中下载最新的CRL更新   http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl   和   http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl
  2.   
  3. 将CodeSignPCA.crl和CodeSignPCA2.crl文件移动到隔离区   系统。
  4.   
  5. 在命令提示符下,输入以下命令以使用certutil   用于更新本地的实用程序   证书存储与CRL   在步骤1中下载:     certutil -addstore CA c:\ CodeSignPCA.crl
  6.         

    CRL文件定期更新,   所以你应该考虑设置一个   下载和重复的重复任务   安装CRL更新。查看   下一次更新时,双击   .crl文件并查看该值   下一个更新字段。

答案 2 :(得分:1)

不确定但是如果延迟时间足够长,初始DNS查找可能是罪魁祸首? (延迟与正常通话有多长时间?)

和/或

此URI是网络内部还是内部网络?

我已经看到在网络中使用负载平衡配置文件时出现了一些奇怪的网络延迟,这些配置设置不正确,防火墙,负载平衡器和其他网络配置文件可能会“对抗”初始连接......

我不是一个很好的网络人,但你可能想看看SA在serverfault.com上对此有何看法......

祝你好运

答案 3 :(得分:0)

SQLCLR第一次加载必要的装配时总会有延迟。 这不仅适用于您的函数MakeWebRequest,也适用于SQLCLR中的任何.NET函数。

答案 4 :(得分:0)

HttpWebRequest是System.Net程序集的一部分,它不是supported libraries的一部分。 我建议使用库System.Web.Services来从SQLCLR内部进行Web服务调用。

答案 5 :(得分:0)

我已经测试过,我的第一次冷运行(SQL服务重启后)在3秒内(不是30次),其他所有运行时间都是0秒。

我用来构建DLL的代码示例:

using System;
using System.Data;
using System.Net;
using System.IO;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace MySQLCLR
{
    public static class WebRequests
    {
        public static void MakeWebRequest(string address, string parameters, int connectTO)
        {
            string returnData;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString()));
            request.Timeout = (int)connectTO;
            request.Method = "GET";
            using (WebResponse response = request.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(responseStream))
                    {
                        returnData = reader.ReadToEnd();
                        reader.Close();
                    }
                    responseStream.Close();
                }
                response.Close();
            }
            SqlDataRecord rec = new SqlDataRecord(new SqlMetaData[] { new SqlMetaData("response", SqlDbType.NVarChar, 10000000) });
            rec.SetValue(0, returnData);
            SqlContext.Pipe.Send(rec);
        }
    }
}