2013-05-07 1 views
2

데이터베이스에 저장 프로 시저를 실행하고 약 225 개의 열이있는 큰 레코드 집합을 반환하는 Windows 스크립트 호스트 스크립트가 있습니다 (열 수가 쿼리에 따라 달라 지므로 미래에는 더 커질 수 있습니다.)큰 레코드 집합을 처리 할 때 "메모리 부족"오류가 발생했습니다

var adUseServer = 2; 
var adUseClient = 3; 
var adOpenForwardOnly = 0; 
var adLockReadOnly = 1; 


var dbc = new ActiveXObject("ADODB.connection") 

dbc.connectionString = "Driver={SQL Server};Server=MYDBSERVER;Database=MYDB;uid=USER;Pwd=PASSWORD;" 
dbc.CursorLocation = adUseClient 
dbc.connectionTimeout = 3600 
dbc.commandTimeout = 3600 
dbc.open 

// Setup test table 
WScript.echo("Setting table..."); 
dbc.execute("IF OBJECT_ID(N'export_test', N'U') IS NOT NULL DROP TABLE export_test;;"); 
dbc.execute("create table export_test (channelID int)"); 

// Changing to 130 works (for me) 
for(var n = 1; n < 131; n++) 
{ 
    dbc.execute("alter table export_test ADD test_" + n + " NVARCHAR(4000) DEFAULT '0' not null"); 
} 



WScript.echo("Starting query..."); 

var rsData = serverQuery("Select * from export_test") 

WScript.echo("Starting loop..."); 

var count = 0; 
while(rsData.eof == 0) 
{ 
    WScript.echo(count++); 
    rsData.moveNext(); 
} 

WScript.echo("All done"); 



function serverQuery(sql) 
{ 
    var rsData = new ActiveXObject("ADODB.recordset"); 
    rsData.CursorLocation = adUseServer; 
    rsData.CursorType = adOpenForwardOnly; 
    rsData.LockType = adLockReadOnly; 
    rsData.MaxRecords = 1; // This makes no difference 
    rsData.open(sql, dbc); 

    return rsData; 
} 

클라이언트 커서를 사용하여이 쿼리를 실행하면 "메모리 부족"오류가 발생합니다. 서버 커서로 실행하면 "이 작업을 완료하는 데 사용할 수있는 저장소가 부족합니다"오류가 발생합니다.

데이터를 줄이려고 시도했지만 많은 행이 반환되지 않고 문제가 지속됩니다.

나는 결과를 '페이징'하려고했으나 반환 된 행을 줄이려고 시도 했으므로 도움이되지 않는다는 두려움 때문에 도움이되지 않았다. 그래서 많은 수의 열이있을 수 있다고 생각한다. (역동적이고 시간이 지남에 따라 갈수록 점점 커질 수 있습니다)이 문제의 근본 원인입니다.

SO 및 다른 사이트에서 읽은 후 데이터베이스 로그 파일 크기를 "제한되지 않은 성장"으로 변경하려고 시도했지만 '최대 크기 2GB'로 되 돌리지 않을 것입니다.하지만 다른 문제가 있습니다. 생각하다).

누구도 이에 대한 더 많은 아이디어 나 통찰력을 갖고 있지 않습니까?

감사합니다.

답변

0

맞습니다. 기본적으로 어딘가에 제한이 있다는 결론을 내 렸습니다. 그래서 내가 한 것은이 작업을 오프로드하고 스크립트 내에서 사용할 수있는 결과 데이터의 JSON 또는 XML 버전을 다시 가져 오기위한 COM 개체를 만드는 것입니다. 관심있는 사람들을위한

는 아래 (지금 단독 dev에 나처럼 사과가 조금 NAFF 경우, 난 더 이상으로 코드 리뷰에 아무도 없다) C# 코드입니다 :

using System; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Data.SqlClient; 
using System.Xml; 

/* 
* To create strong name key for signing: "C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\sn" -k SQLInterchange_Key.snk" 
*/ 


namespace SQLInterchange 
{ 
    [Guid("4E97C259-80EC-40dc-8F7D-DB56BE9F123E")] 
    public interface ISQLInterchange 
    { 
    [DispId(1)] 
    bool Open(string databaseServer, string databaseName, string userID, string userPassword); 

    [DispId(2)] 
    void Close(); 

    [DispId(3)] 
    bool ExecuteRecordset(string selCommand); 

    [DispId(4)] 
    void CloseRecordset(); 

    [DispId(5)] 
    bool Execute(string selCommand); 

    [DispId(6)] 
    string GetJSONData(); 

    [DispId(7)] 
    string GetXMLData(string recordElementName, bool encoded); 
    } 


    // Events interface Database_COMObjectEvents 
    [Guid("31A125AA-81D5-495b-86E6-7A4B24B08BAA"), 
    InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    public interface SQLInterchange_Events 
    { 
    } 


    [Guid("6B0B6A04-3BAF-4e14-9770-A0C10425E2CE"), 
    ClassInterface(ClassInterfaceType.None), 
    ComSourceInterfaces(typeof(SQLInterchange_Events))] 
    public class Connection : ISQLInterchange 
    { 
    private SqlConnection _connection = null; 
    private SqlDataReader _reader = null; 

    public Connection() 
    { 
    } 

    public bool Open(string databaseServer, string databaseName, string userID, string userPassword ) 
    { 
     // no need to throw as it throws a com compatible exception automatically 

     string myConnectString = "user id=" + userID + ";password=" + userPassword +";Database=" + databaseName + ";Server=" + databaseServer + ";Connect Timeout=30"; 
     _connection = new SqlConnection(myConnectString); 
     _connection.Open(); 

     return true; 
    } 

    public bool ExecuteRecordset(string selCommand) 
    { 
     if(_reader != null) 
     _reader.Close(); 

     SqlCommand myCommand = new SqlCommand(selCommand); 
     myCommand.Connection = _connection; 
     myCommand.CommandTimeout = 3600; 
     myCommand.ExecuteNonQuery(); 
     _reader = myCommand.ExecuteReader(); 
     return true; 
    } 


    public bool Execute(string selCommand) 
    { 
     if(_reader != null) 
     _reader.Close(); 

     SqlCommand myCommand = new SqlCommand(selCommand, _connection); 
     myCommand.CommandTimeout = 3600; 
     int rows = myCommand.ExecuteNonQuery(); 
     return true; 
    } 


    public void Close() 
    { 
     if(_connection != null) 
     _connection.Close(); 
    } 


    public void CloseRecordset() 
    { 
     if(_reader != null) 
     _reader.Close(); 
    } 


    public string GetJSONData() 
    { 
     StringBuilder sb = new StringBuilder(); 
     sb.Append("["); 

     if(_reader != null) 
     { 
     int count = _reader.FieldCount; 

     StringBuilder sbRecord = new StringBuilder(); 
     while(_reader.Read()) 
     { 

      if(sbRecord.Length > 0) 
      { 
      sbRecord.Append(","); 
      } 

      sbRecord.Append("{"); 

      // get the results of each column 
      for(int n = 0; n < count; n++) 
      { 
      string name = _reader.GetName(n); 
      string data = Convert.ToString(_reader[ n ]); 

      sbRecord.Append("\"" + _safeJSONElementName(name) + "\":\""); 

      sbRecord.Append(_safeJSON(data)); 

      sbRecord.Append("\""); 

      if(n + 1 < count) 
      { 
       sbRecord.Append(","); 
      } 
      } 

      sbRecord.Append("}"); 
     } 

     sb.Append(sbRecord.ToString()); 
     } 

     sb.Append("]"); 

     return sb.ToString(); 
    } 


    public string GetXMLData(string recordElementName, bool encoded) 
    { 
     _lt = "<"; 
     _gt = ">"; 

     if(encoded) 
     { 
     _lt = "&lt;"; 
     _gt = "&gt;"; 
     } 

     StringBuilder sb = new StringBuilder(); 

     if(_reader != null) 
     { 
     int count = _reader.FieldCount; 

     while(_reader.Read()) 
     { 
      _addXMLElement(sb, recordElementName, 1, true); 

      // get the results of each column 
      for(int n = 0; n < count; n++) 
      { 
      string name = _reader.GetName(n); 
      string data = Convert.ToString(_reader[ n ]); 

      _addXMLElement(sb, name, 2, false); 

      sb.Append(_escapeXML(data)); 

      _addXMLElement(sb, "/" + name, 0, true); 
      } 

      _addXMLElement(sb, "/" + recordElementName, 1, true); 
     } 
     } 

     return sb.ToString(); 
    } 


    private string _safeJSON(string s) 
    { 
     s = s.Replace("\n", "\\n"); 
     s = s.Replace("\r", "\\r"); 
     s = s.Replace("\t", "\\t"); 
     s = s.Replace("\"", "\\\""); 
     return s; 
    } 

    private string _safeJSONElementName(string s) 
    { 
     s = s.Replace(".", "_"); 
     s = s.Replace(" ", "_"); 
     return s; 
    } 


    private string _lt = "<"; 
    private string _gt = ">"; 

    private void _addXMLElement(StringBuilder sb, string s, int tabs, bool last) 
    { 
     for(int n = 0; n < tabs; n++) 
     { 
     sb.Append("\t"); 
     } 
     sb.Append(_lt); 
     sb.Append(s); 
     sb.Append(_gt); 
     if(last) sb.Append("\n"); 
    } 

    private string _escapeXML(string unescaped) 
    { 
     XmlDocument doc = new XmlDocument(); 
     var node = doc.CreateElement("root"); 
     node.InnerText = unescaped; 
     return node.InnerXml; 
    } 
    } 

} 
관련 문제