hawkmaster: SQL Server MARS ? Connection is busy

Hallo zusammen,
Ich versuche gerade eine Migration von MySQL zu SQL Server 2008. Die ersten Hürden sind genommen.
Ich verbinde mit PDO und ODBC zum SQL Server:
$DBO = new PDO('odbc:MyDatabase');

Ich bekomme nun diese Fehlermdelung:

General error: 0 [Microsoft][SQL Server Native Client 10.0]Connection is busy with results for another command

Verursacht wird diese laut Zeilennummer von "hasChildKats".

Ich habe nun schon ewig gegoogelt und in vielen Beiträgen gelesen. Irgendwie hat dies etwas damit zu tun, dass der SQL Server "mehrere Verbindungen" aufmacht?
Ich kann den Fehler beheben indem ich in den Connection String "MARS_Connection=yes" einfüge.
Andererseits lese ich aber das gerade das aktivierte MARS Probleme bereiten kann. Es ist ja Default auf OFF.

An den SQL Abfragen ansich ist ja vermutlich nichts falsch.

Kann mir jemand ein wenig Hintergrundinfos zu MARS geben bzw. ob es ok ist, wenn man es aktiviert?

  
function getSubdirIds($parentid){//finds all Subdirs , returns an array with all subdir ids  
global $DBO;  
$subdirids = "";  
$sql_ids = $DBO->query("SELECT DirectoriesID,Level FROM directories WHERE ParentID = '$parentid' ORDER BY DirectoriesID");  
    while($rowids = $sql_ids->fetch(PDO::FETCH_ASSOC)) {  
		  if(hasChildKats($rowids['DirectoriesID'])) {  
....  
function hasChildKats($katID) {  
global $DBO;  
$einlesen = $DBO->query("SELECT DirectoriesID FROM directories WHERE ParentID = '$katID' ");  
$sql_data = $einlesen->fetch(PDO::FETCH_ASSOC);  
if($sql_data){  
return true;  
}else{  
return false;  
}  
}  
  

vielen Dank und viele Grüße
hawk

  1. Moin Moin!

    General error: 0 [Microsoft][SQL Server Native Client 10.0]Connection is busy with results for another command

    Du hast mehr als ein Statement am Laufen. SQL Server kann aber immer nur aus einem Statement lesen. Das ist eine Beschränkung des Netzwerk-Protokolls vom SQL-Server. Es gibt Workarounds, aber die stinken ganz fürchterlich. Generell hast Du zwei Möglichkeiten: Entweder sorgst Du dafür, dass im Programmcode immer nur ein Statement zwischen prepared und finished steht, oder Du nimmst für parallele Abfragen mehrere DB-Verbindungen. Letzteres sabotiert Transaktionen und führt gelegentlich zu Deadlocks, die der SQL Server durch ungezieltes abtöten irgendeiner Verbindung "behebt".

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Genau diese Beschränkung lässt sich mit MARS (multiple active result sets) umgehen.

      Bisher hatte ich keine Probleme mit MARS, weder in Verbindung mit .NET noch mit PHP.
      Deadlocks sollten bei Lesezugriffen eher kein Problem darstellen. ;)

      1. Hallo Patrick,
        auch dir vielen Dank.

        Bisher hatte ich keine Probleme mit MARS, weder in Verbindung mit .NET noch mit PHP.

        Dann werde ich es mal versuchen mit aktiviertem MArs. Ich wüsste auch garnicht wie ich meinen Programmcode anders aufbauen müsste. Mit MySQL läuft der einwandfrei.

        vielen Dank und viele Grüße
        hawk

    2. Hallo Alexander,

      vielen Dank für deine Hilfe.

      Entweder sorgst Du dafür, dass im Programmcode immer nur ein Statement zwischen prepared und finished steht, oder Du nimmst für parallele Abfragen mehrere DB-Verbindungen.

      Hmm, verstehe ich nicht so ganz. Dein Beispiel zielt ja auf die ausschließliche Nutzung von Prepared Statements oder?
      Das verwende ich ja bisher garnicht.
      Und "parallele Abragen"? Eigentlich wird doch der PHP Code sequentiell und nacheinander abgearbeitet? Wie sollte man denn sowas programmtechnisch umsetzen?

      vielen Dank und viele Grüße
      hawk

      1. Was Alexander meint, ist folgendes:
        Du öffnest zuerst mit $DBO->query("SELECT DirectoriesID,Level [..] ein Result-Set.
        Anschließend wird für jede Zeile die Funktion hasChildKats() aufgerufen.
        In dieser Funktion wird mit $DBO->query("SELECT DirectoriesID FROM [...] erneut ein Result-Set geöffnet. Und weil gleichzeitig noch das erste Result-Set geöffnet ist, funktioniert das ohne MARS nicht.

        Die Lösung mit den parallelen Verbindungen würde so funktionieren, dass du in der Funktion hasChildKats() eine neue Connection aufbaust, wodurch sich die beiden Queries nicht in die Quere kommen.

        Übrigens könntest du in deinem Beispiel eine Abfrage (mehr oder weniger) vermeiden, nämlich über eine Unterabfrage:

        SELECT  
          DirectoriesID,  
          Level,  
          (SELECT COUNT(subdirectories.DirectoriesID) FROM directories AS subdirectories WHERE subdirectories.ParentID = directories.DirectoriesID) AS NumSubDirectories  
        FROM  
          directories  
        WHERE  
          ParentID = '$parentid'  
        ORDER BY  
          DirectoriesID
        

        In NumSubDirectories steckt dann jeweils die Anzahl der Unterordner der aktuellen Zeile.