Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Δεν πεθαίνει το άτιμο το SqlCommand!

Îåêßíçóå áðü ôï ìÝëïò Παναγιώτης Καναβός. Τελευταία δημοσίευση από το μέλος Παναγιώτης Καναβός στις 24-09-2006, 19:18. Υπάρχουν 7 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  19-09-2006, 19:30 16938

    Δεν πεθαίνει το άτιμο το SqlCommand!

    Λοιπόν, συνάντησα το εξής κουφό. Προσπαθώ να εκτελέσω ασύγχρονα ένα πολύ βαρύ stored procedure (ώρες!) , καλώντας το με την BeginExecuteNonQuery(). Η βάση είναι SQL Server 2000, το ADO.NET 2.0 και ο provider ο SqlClient. Το stored procedure εκτελείται κανονικότατα και επιστρέφει τα αποτελέσματα που περιμένω. Θέλω όμως ο χρήστης να έχει και τη δυνατότητα να διακόπτει την εκτέλεση του.

    Αμ δε! Δοκίμασα να καλέσω την Cancel του SqlCommand, η οποία όμως μπλοκάρει μέχρι να τελειώσει το stored procedure! Αν δεν καλέσω την Cancel αλλά τερματίσω την εφαρμογή, το SqlCommand εξακολουθεί να εκτελείται στο Thread Pool!

    Δοκίμασα να φτιάξω ένα δικό μου thread και να εκτελέσω εκεί το SqlCommand. Όταν ο χρήστης ζητάει ακύρωση, καλώ την Thread.Abort και λογικά περιμένω να εμφανιστεί ένα ThreadAbortException. Πάλι τίποτα! Και αυτή τη φορά, το ThreadAbortException εμφανίζεται μόνο όταν τελειώσει το SqlCommand!

    Τώρα κάτι άρχισα να ψυλιάζομαι. Απ' όσο ξέρω, το abort δεν είναι άμεσο όταν χρησιμοποιεί κανείς Interop, είτε COM είτε με P/Invoke. Εγώ όμως χρησιμοποιώ SqlClient!

    Έχει κανείς καμμία ιδέα?


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  19-09-2006, 20:10 16939 σε απάντηση της 16938

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

    Χμμμ... Δύο περιπτώσεις μπορώ να σκεφτώ... Η πρώτη είναι να στέλνεις το cancel αλλά επειδή το tread που ξεκίνησε το Execute είναι blocked, να το λαμβάνει αφού έχει τελειώσει η δουλειά. Δοκίμασες να το υλοποιήσεις όπως στο παράδειγμα του MSDN, στέλνοντας το cancel από άλλο thread?

     
       Public Sub Thread_Cancel()
            Command.Cancel()
       End Sub

       Sub DoTheJob()

          ...
          ... (start the async job here)
          ...
          Dim rThread2 As Thread = New Thread( _
          New ThreadStart(AddressOf Thread_Cancel))
          rThread2.Start()
          rThread2.Join()

       End Sub

    H δεύτερη είναι να μην μπορεί πραγματικά να κάνει cancel. Σε κάποιο blog post είχα διαβάσει ότι η Cancel θα *προσπαθήσει* να κάνει cancel αλλά δεν είναι σίγουρο ότι θα τα καταφέρει. Εξαρτάται από το state του server (ότι κι αν σημαίνει αυτό Big Smile)

     


    Vir prudens non contra ventum mingit
  •  19-09-2006, 23:59 16947 σε απάντηση της 16939

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

    Εγώ θα έκανα κάτι άλλο. Θα είχα μια συγκεκριμένη εγγραφή στη βάση (μία στήλη μιας γραμμής) η οποία όταν πάρει μια συγκεκριμένη τιμή, η ίδια η stored procedure θα σταματάει τον εαυτό της. Προφανώς για να κρατάει τόσο πολύ φαντάζομαι ότι έχεις κάποιο loop. Μπορείς να ελέγχεις την τιμή αυτή σε κάθε iteration ή μια φορά σε 10 iterations κλπ.

    Οπότε όταν θέλεις να διακόψεις την εκτέλεση θα θέτεις αυτή την τιμή. Έτσι η stored procedure θα σταματάει και πολύ πιο ομαλά και φυσιολογικά.


    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
  •  20-09-2006, 14:00 16974 σε απάντηση της 16947

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

    Loop! Φτού-φτου-φτου! Όταν υπάρχει το select και το join, δεν χρειάζεται το loop! Σοβαρά τώρα, η χρήση ενός πίνακα σαν flag δημιουργεί πολύ περισσότερα προβλήματα απ' όσα λύνει. Αμέσως- αμέσως τίθεται θέμα locking μεταξύ όσων διαβάζουν και όσων γράφουν στο row. Ένα λάθος να κάνει κάποιος, και θα κλειδώσει όλους όσους χρησιμοποιούν το flag. Ο κώδικας αναγκαστικά θα γίνει πολύ πιο περίπλοκος,

    Όπως και να έχει, στη δική μου περίπτωση έχω βαρειά insert-select-update για να δημιουργήσω ένα πίνακα για reporting. Σκοπός είναι αυτό το stored procedure να τρέχει γρήγορα, αλλά να μπορεί να το ακυρώσει ο χρήστης αν χρειαστεί. Η απορία μου είναι γιατί μπλοκάρει το Cancel, και γιατί δεν συμπεριφέρεται το Thread.Abort όπως περίμενα.
    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  20-09-2006, 14:13 16975 σε απάντηση της 16974

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

    Δοκίμασες αυτό που σου πρότεινα; Παίζει;
    Vir prudens non contra ventum mingit
  •  20-09-2006, 14:24 16978 σε απάντηση της 16974

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

     pkanavos wrote:
    Loop! Φτού-φτου-φτου! Όταν υπάρχει το select και το join, δεν χρειάζεται το loop! Σοβαρά τώρα, η χρήση ενός πίνακα σαν flag δημιουργεί πολύ περισσότερα προβλήματα απ' όσα λύνει. Αμέσως- αμέσως τίθεται θέμα locking μεταξύ όσων διαβάζουν και όσων γράφουν στο row. Ένα λάθος να κάνει κάποιος, και θα κλειδώσει όλους όσους χρησιμοποιούν το flag. Ο κώδικας αναγκαστικά θα γίνει πολύ πιο περίπλοκος,

    Καλά ντε! Μη βαράς! Δεν ξέρω τι κάνει η sp σου; Εγώ το είπα γιατί ο καλύτερος τρόπος να σταματήσεις ένα thread είναι να το ειδοποιήσεις να σταματήσει μόνο του. Σίγουρα ο κώδικας θα γινόταν λίγο πιο περίπλοκος, αλλά αν γραφόταν σωστά δεν θα υπήρχε περίπτωση να μπερδευτούν τα threads.


    Dimitris Papadimitriou
    Software Development Professional
    dotNETZone.gr News

    Οι απαντήσεις παρέχονται για συγκεκριμένες ερωτήσεις και χωρίς καμιά εγγύηση. Διαβάστε επίσης τους όρους χρήσης.
  •  20-09-2006, 23:19 16996 σε απάντηση της 16978

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

    Τελικά δοκίμασες τη λύση που πρότεινε ο KelMan ?? Φαίνεται να είναι το πάγιο recommendation για όταν θες να κάνεις cancel αν και στο MSDN λέει οτι το Cancel() " προσπαθεί να ακυρώσει το command αν μπορεί, χωρίς να πετάει exception αν δεν τα καταφέρει " ... πάντως και στο ADO.NET Primer που είδα, παλι το ίδιο λέει ... κάλεσε την Cancel απο άλλο thread:

    9 Tip: Use the SqlCommand.Cancel() method to cancel long running or rogue queries. Create another thread and call the Cancel method on the running command. This will cancel the locally running command and notify the server to kill the command process, thus freeing up resources.


    Άντε, και πες πας κιόλας ε;

    Angel
    O:]
  •  24-09-2006, 19:18 17122 σε απάντηση της 16996

    Απ: Δεν πεθαίνει το άτιμο το SqlCommand!

    Συγγνώμη για την καθυστέρηση, αλλά πλέον δεν βρίσκω χρόνο ούτε για φτάρνισμα μέσα στη βδομάδα!

    Λοιπόν, επιβεβαίωσα ότι την Cancel πρέπει να την καλέσεις από άλλο thread. Και αυτό μεν είναι απόλυτα λογικό όταν μιλάμε για σύγχρονη εκτέλεση (αφού έχει ήδη μπλοκάρει το thread) αλλά ακούγεται περίεργο για ασύγχρονη εκτέλεση. Αυτό όμως εξηγείται αν σκεφτεί κανείς ότι όταν εκτελεί κανείς ασύγχρονα ένα command, ΔΕΝ εκτελείται σε διαφορετικό thread, όπως γινόταν στο ΝΕΤ 1.1, αλλά στο αρχικό thread. Η ασύγχρονη συμπεριφορά επιτυγχάνεται στο επίπεδο δικτύου. Το ADO.NET στέλνει στοιχεία στον SQL Server και περιμένει να λάβει callbacks από το driver δικτύου όταν ολοκληρωθεί η επεξεργασία από τον SQL Server. Το αρχικό thread συνεχίζει να εκτελείται μέχρι να ολοκληρωθεί η κλήση προς τον SQL Server. Αν δωθεί εντολή Cancel από το αρχικό thread, αυτή θα πρέπει να σταλεί στον SQL Server αφού ολοκληρωθεί η κλήση που εκκρεμμεί

    Όταν τώρα καλούμε την εντολή cancel, το ADO.NET λέει στον SQL Server να ακυρώσει την εκτέλεση της εντολής που εκτελούσε. Αν η εντολή ήταν ένα insert ή update το οποίο επηρέασε μερικά μιλιούνια εγγραφές, η ακύρωση θα καθυστερήσει μέχρι να γίνουν rollback οι αλλαγές. Η Cancel περιμένει να γίνουν όλα τα rollback πριν επιστρέψει για να μπορούμε να εκτελέσουμε νέες εντολές αμέσως μετά. Αν η Cancel επέστρεφε πριν προλάβουν να εκτελεστούν τα rollback, οι επόμενες εντολές δεν θα μπορούσαν να αγγίξουν τους πίνακες που εμπλέκονταν στην προηγούμενη εντολή και θα μπλοκάραν και αυτές αναγκαστικά.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems