Kann ich eine lange laufende gespeicherte proc über mehrere CPUs ausbreiten?

[Auch auf SuperUser – https://superuser.com/questions/116600/can–spead-out-a-long-Running-stored-proc-accross-multiple-cpus ]

Ich habe eine gespeicherte Prozedur in SQL-server die bekommt, und entschlüsselt einen datablock. (Kreditkarten in diesem Fall.)

Die meisten der time, die performance ist erträglich, aber es gibt ein paar Kunden, wo der process ist schmerzhaft langsam, buchstäblich 1 Minute zu vervollständigen. (Nun, 59377ms, um von SQL server zurückzukehren, um genau zu sein, aber es kann um ein paar hundert ms basierend auf Last variieren)

Wenn ich den process anschaue, sehe ich, dass SQL nur einen einzigen Proc verwendet, um den ganzen process durchzuführen, und normalerweise nur proc 0.

Gibt es eine Möglichkeit, ich kann meine gespeicherten Proc ändern, so dass SQL kann Multi-Thread der process? Ist es sogar möglich, zu betrügen und die Anrufe in der Hälfte zu brechen, (Top 50%, unten 50%), und verbreiten Sie die Last, als ein grober Hack? (nur spucken hier)

Meine gespeicherte proc:

USE [Commerce] GO /****** Object: StoredProcedure [dbo].[GetAllCreditCardsByCustomerId] Script Date: 03/05/2010 11:50:14 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[GetAllCreditCardsByCustomerId] @companyId UNIQUEIDENTIFIER, @DecryptionKey NVARCHAR (MAX) AS SET NoCount ON DECLARE @cardId uniqueidentifier DECLARE @tmpdecryptedCardData VarChar(MAX); DECLARE @decryptedCardData VarChar(MAX); DECLARE @tmpTable as Table ( CardId uniqueidentifier, DecryptedCard NVarChar(Max) ) DECLARE creditCards CURSOR FAST_FORWARD READ_ONLY FOR Select cardId from CreditCards where companyId = @companyId and Active=1 order by addedBy desc --2 OPEN creditCards --3 FETCH creditCards INTO @cardId -- prime the cursor WHILE @@Fetch_Status = 0 BEGIN --OPEN creditCards DECLARE creditCardData CURSOR FAST_FORWARD READ_ONLY FOR select convert(nvarchar(max), DecryptByCert(Cert_Id('Oh-Nay-Nay'), EncryptedCard, @DecryptionKey)) FROM CreditCardData where cardid = @cardId order by valueOrder OPEN creditCardData FETCH creditCardData INTO @tmpdecryptedCardData -- prime the cursor WHILE @@Fetch_Status = 0 BEGIN print 'CreditCardData' print @tmpdecryptedCardData set @decryptedCardData = ISNULL(@decryptedCardData, '') + @tmpdecryptedCardData print '@decryptedCardData' print @decryptedCardData; FETCH NEXT FROM creditCardData INTO @tmpdecryptedCardData -- fetch next END CLOSE creditCardData DEALLOCATE creditCardData insert into @tmpTable (CardId, DecryptedCard) values ( @cardId, @decryptedCardData ) set @decryptedCardData = '' FETCH NEXT FROM creditCards INTO @cardId -- fetch next END select CardId, DecryptedCard FROM @tmpTable CLOSE creditCards DEALLOCATE creditCards 

Was ist mit der Verwendung von FOR XML, um eine Verkettung in einer einzigen korrelierten Unterabfrage durchzuführen:

 DECLARE @cards TABLE ( cardid INT NOT NULL ,addedBy INT NOT NULL ) DECLARE @data TABLE ( cardid INT NOT NULL ,valueOrder INT NOT NULL ,encrypted VARCHAR(MAX) NOT NULL ) INSERT INTO @cards VALUES ( 0, 1 ) INSERT INTO @cards VALUES ( 1, 0 ) INSERT INTO @data VALUES ( 0, 0, '0encrypted0' ) INSERT INTO @data VALUES ( 0, 1, '0encrypted1' ) INSERT INTO @data VALUES ( 0, 2, '0encrypted2' ) INSERT INTO @data VALUES ( 1, 0, '1encrypted0' ) INSERT INTO @data VALUES ( 1, 1, '1encrypted1' ) -- INSERT INTO output_table () SELECT cardid, decrypted FROM @cards AS cards OUTER APPLY ( SELECT REPLACE(encrypted, 'encrypted', 'decrypted') + '' -- Put your UDF here FROM @data AS data WHERE data.cardid = cards.cardid ORDER BY data.valueOrder FOR XML PATH('') ) AS data ( decrypted ) ORDER BY cards.addedBy DESC 

Dies kann eine bessere Frage für die SuperUser-Gruppe (DBA) sein

Denken Sie daran, dass Kreditkartennummern sehr gut ist – die letzte Ziffer in Visa / MasterCard 16-stellige CC's ist ein Prüfsummenwert. Hast du zum Beispiel die Roll-your-own-Parallelität in Betracht gezogen, indem du bei jedem Thread die CC-Nummern greifst, wo modulo (4) = thread_id? Angenommen, n CPUs / coree / was auch immer sie sie heute anrufen, würden Sie nicht mehr als 4 (2 * coree) parallel verarbeitende Threads wollen.

Ja – schreibe die Cursor als Set-basierte Abfrage um, und der SQL server-Optimierer sollte sich je nach Größe der zugrunde liegenden data automatisch parallelisieren (oder nicht). Keine "spezielle" dev Arbeit ist erforderlich, um SQL server verwenden Parallelität, außer einige grundlegende Best Practice wie Vermeidung von Cursors. Es wird automatisch entscheiden, ob es möglich ist, parallele Threads auf mehrere Procs zu verwenden, und wenn es nützlich ist, dies zu tun, und dann kann es die Arbeit für Sie zur Laufzeit aufteilen.