【问题标题】:What's the fastest way to check the availability of a SQL Server server?检查 SQL Server 服务器可用性的最快方法是什么?
【发布时间】:2010-03-24 21:20:59
【问题描述】:

我有一个在多个位置使用的 MS Access 程序。它连接到 MS SQL Server 表,但每个位置的服务器名称不同。我正在寻找测试服务器是否存在的最快方法。我目前使用的代码如下所示:

ShellWait "sc \\" & ServerName & " qdescription MSSQLSERVER > " & Qt(fn)
FNum = FreeFile()
Open fn For Input As #FNum
Line Input #FNum, Result
Close #FNum
Kill fn

If InStr(Result, "SUCCESS") Then ...

ShellWait:执行一个shell命令并等待它完成
Qt:将字符串用双引号括起来
fn: 临时文件名变量

我针对一个服务器名称列表(其中只有一个通常可用)运行上述代码。如果服务器可用,该代码大约需要一秒钟,而对于每个不可用的服务器,该代码大约需要 8 秒钟。如果可能的话,我想降低这两个值,但尤其是失败的情况,因为这种情况最常发生。

【问题讨论】:

    标签: sql-server ms-access vba


    【解决方案1】:

    您可以尝试创建一个 ADO 连接并将超时设置为某个较低的值,例如(未经测试):

    Dim cn As ADODB.Connection 
    Set cn = New ADODB.Connection
    cn.ConnectionTimeout = 4     ' Wait at most 4 seconds for connection
    cn.ConnectionString = "Provider=SQLOLEDB.1;Data Source=" & ServerName & ";Integrated Security=SSPI"
    
    On Error Resume Next
    cn.Open
    If Err.Number > 0 Then
        ...
    Else
        cn.Close
        ...
    End If
    On Error Goto 0   ' replace 0 with previously used error handler
    

    【讨论】:

    • 我承认我没有尝试这个选项,因为我目前使用 DAO 作为我选择的参考,并且不想处理添加此参考可能引起的任何并发症(尤其是由于 ADO 和 DAO 之间的大量重叠)。不过,这看起来确实是合理的。
    • 我只是尝试通过 ADO 进行连接,如果失败,我会通知用户。
    • 在 Access 中使用 ADO 不需要 ADO 的引用。您可以使用 Application.CreateObject 进行后期绑定来初始化 ADO 顶级连接对象,也可以使用 CurrentProject.Connection 而无需使用后期绑定进行初始化。
    【解决方案2】:

    我很抱歉,因为我是新来的,所以我很抱歉,但我想提出一个建议。您实际上可以捕获带壳命令的输出,而无需使用 windows api 使用中间文本文件。我创建了一个小类文件,它干净地包装了它(link)。

    使用它,您可以将代码重构为此而不必担心读取文件带来的额外头痛。

    Function SQLServerDBExists(ServerName As String, DbName As String) As Boolean
    Dim Result As String
    Dim cls as new clsRunApp
    
    On Error GoTo Err_SQLServerDBExists
    
    'Check for existence of the server
    Result = cls.RunAppWait_CaptureOutput("nslookup " & ServerName)
    If InStr(Result, "Non-existent domain") Then
        SQLServerDBExists = False
        GoTo Exit_SQLServerDBExists
    End If
    
     Result = cls.RunAppWait_CaptureOutput("sc \\" & ServerName & " qdescription MSSQLSERVER")
    If InStr(Result, "SUCCESS") Then
        With PassThru("SELECT Name FROM sysdatabases " & _
                      "WHERE Name='" & DbName & "'", "master", ServerName)
            SQLServerDBExists = (Not .EOF)
        End With
    End If
    
    Exit_SQLServerDBExists:
        Exit Function
    Err_SQLServerDBExists:
        LogError Err.Number, Err.Description, "SQLServerDBExists", "AttachToSQL", , , Erl
        Resume Exit_SQLServerDBExists
    End Function
    

    【讨论】:

    • 一点也不出格。这是一个很棒的课程模块。不过,我遇到了一个问题:nslookup 使用 RunAppWait_CaptureOutput 方法返回的输出与从命令提示符本身或使用我的临时文件 hack 返回的输出不同。当我在命令提示符处运行“nslookup wcdbs02”(其中 wcdbs02 是已知的良好服务器)时,我得到了完整的服务器名称和 IP 地址。当我使用 RunAppWait 运行它时,我收到以下消息:'*** UnKnown can't find wcdbs02: No response from server'。因此,除非我遗漏了什么,否则 nslookup 似乎与 RunAppWait 不兼容。
    • 你是对的。我从来没有尝试过用它来使用 nslookup,但我得到了相同类型的响应。我怀疑这与流程的创建方式有关。以后有时间我会多看的。
    • 这很奇怪。它似乎只影响 dns 查找。其他一切正常。您可以试试这个作为解决方法:vbforums.com/… 并使用 NameToAddress 方法 ""
    • mwolfe:问题已在此线程中解决:stackoverflow.com/questions/2188885/… 只需在 RunAppWait_CaptureOutput 中编辑 createprocess 行以添加 ByVal 即可。
    • 像魅力一样工作。希望我能不止一次投票。
    【解决方案3】:

    我最终确定的解决方案是使用 nslookup.exe 作为我的 sc.exe 命令的前导。如果 SQL Server 服务器不存在,nslookup 会立即告诉我。进行此更改将 SQL Server 查找失败所需的时间从大约 8 秒减少到不到 1 秒。成功案例实际上稍长一些,但并不明显。对于那些可能感兴趣的人,这是我的最终解决方案(希望我的个人功能 [ShellWait, Qt, PassThru, LogError] 的目的很明显):

    更新:我已经更新了函数以合并 dmaruca 的 clsRunApp(我最喜欢的新类模块)和 Philippe 提出的关于在断开模式下工作的问题。结果比我最初发布的要好得多,我要感谢他们俩的贡献。这是现在的功能:

    Function SQLServerDBExists(ComputerName As String, DbName As String) As Boolean
    Const LocalHost = "127.0.0.1"
    Dim Result As String, RunApp As New clsRunApp
    
        On Error GoTo Err_SQLServerDBExists
    
        If ComputerName <> LocalHost And _
           ComputerName <> "." And _
           ComputerName <> Environ("COMPUTERNAME") Then
            'Check for existence of the server using Name Server Lookup'
            Result = RunApp.RunAppWait_CaptureOutput("nslookup " & ComputerName)
            If InStr(Result, "Non-existent domain") Or _
               InStr(Result, "Default servers are not available") Then
                SQLServerDBExists = False
                GoTo Exit_SQLServerDBExists
            End If
        End If
    
        Result = RunApp.RunAppWait_CaptureOutput("sc \\" & ComputerName & " qdescription MSSQLSERVER")
        If InStr(Result, "SUCCESS") Then
            With PassThru("SELECT Name FROM sysdatabases " & _
                          "WHERE Name='" & DbName & "'", "master", ComputerName)
                SQLServerDBExists = (Not .EOF)
            End With
        End If
    
    Exit_SQLServerDBExists:
        Exit Function
    Err_SQLServerDBExists:
        LogError Err.Number, Err.Description, "SQLServerDBExists", "AttachToSQL"
        Resume Exit_SQLServerDBExists
    End Function
    

    注意:我意识到 Environ("COMPUTERNAME") 不是 100% 可靠的确定计算机名称的方法,因此如果您愿意,请随时用您自己的代码替换它。我认为惰性方法足以满足其目的。

    【讨论】:

    • 为什么对 clsRunApp (vbforums.com/showthread.php?p=3720615) 如此兴奋?对于一个不太困难的问题,似乎是一个过于复杂的解决方案。并且使用它与您决定使用 Environ() 而不是 API 调用来获得 100% 可靠的机器名称完全矛盾。可以通过搜索 mvps.org/access 找到其代码。
    • @Fenton:你能指出一个不太复杂的解决方案来解决从命令行程序捕获输出的问题吗?
    • 我只能指出那些你似乎拒绝接受的东西。
    • 如果您在谈论 mvps.org/access,我在那里进行了搜索,发现最接近的是 ShellWait 函数(我已经使用了一段时间了)。我很欣赏 clsRunApp 模块,因为我过去对问题的解决方案是调用 ShellWait 并将输出重定向到临时文本文件...等待临时文本文件存在并完成其写入过程...加载一行或多行从临时文件到变量...杀死临时文件。这对我来说相当可靠,但总是觉得很笨拙。我仍然希望你能指出我认为我已经拒绝的那些。
    【解决方案4】:

    我这样做的方式(在遥远的过去)是使用链接表并拥有一个允许在运行时一次性选择服务器的用户表单。或者,您可以将服务器名称放在配置文件中,并使用它动态创建连接字符串。

    【讨论】:

      【解决方案5】:
      telnet servername 1433
      

      【讨论】:

      • 这当然只有在 SQL Server 实例位于其默认端口时才有效。
      【解决方案6】:

      此处提出的解决方案适用于特定条件,即计算机已联网且 dns 服务器可用。如果您的应用程序应该在连接(您可以连接到“主”服务器之一)和断开模式(您连接到数据库的本地副本)下工作,则此解决方案不会这样做。

      到目前为止,我们通用、高效但(我必须承认)不太聪明的解决方案是拥有一个客户端连接表(实际上是 xml 文件 - 每个连接一个 - 在 app 文件夹中)并让用户选择启动时的连接。根据用户、工作地点和离线工作能力,我们可以选择在他的计算机上安装哪些 xml 连接字符串。

      我们的想法是(当我们有时间时)使用计算机的 IP 地址来识别/计算可用的“最佳”数据库服务器:如果计算机未联网,则连接将设置为“本地主机”。否则,将在为数据库服务器提供预定 ip 后缀的网络上“即时”建立连接。因此,当一台计算机的 ip 是 aaa.bbb.ccc.ddd 时,机器会知道它必须连接到 aaa.bbb.120.132,其中 120.132 是预定义的数据库服务器后缀。

      【讨论】:

        猜你喜欢
        • 2011-03-16
        • 1970-01-01
        • 2020-01-09
        • 2019-09-24
        • 2016-08-17
        • 1970-01-01
        • 1970-01-01
        • 2016-11-20
        • 2011-01-11
        相关资源
        最近更新 更多