2010-11-26 15 views
1

J'ai une procédure sql dans laquelle j'utilise un curseur, mais c'est vraiment très lent. Je cherche à améliorer la vitesse en utilisant un fonctionnement basé sur un ensemble ou de telles choses, mais je n'ai aucune idée comment l'appliquer à cette procédure spécifique:Amélioration pour ce curseur SQL - C'est vraiment lent!

declare @isMulti bit 
    declare @QuestionID int 
    declare db_cursor cursor FAST_FORWARD for 
     select distinct QuestionID 
     from tblQuestions (nolock) 
     where [email protected] 

    open db_cursor 
    fetch next from db_cursor into @QuestionID 

    while @@FETCH_STATUS = 0 
    begin 
       --check if @isMulti is true or not for the current question 
       if(@isMulti=1) 
       begin 
        update tblAnswers 
        set col1 = 1, col2 = 1, col3 = (select count(*) from tblAnswers where [email protected] and [email protected]) 
       end 
       else if(@isMulti=0) 
       begin 
        update tblAnswers 
        set col1 = AnswerID, col2 = 1, col3 = (select LEN(count(*)) from tblAnswers where [email protected] and [email protected]) 
       end 

       fetch next from db_cursor into @QuestionID 
    end 
close db_cursor 
deallocate db_cursor 

Merci pour toute aide fournie!

+0

Qu'essayez-vous de faire avec cette procédure? Peut-être qu'une simple requête de mise à jour peut suffire. – vdrmrt

+0

Je vérifie si une question est multi ou non, puis je mets à jour ces questions en fonction de ces informations. La table des questions ne contient pas de colonne spécifiant si elle est multi ou non, je dois appeler une fonction sur l'identifiant de la question en cours dans le curseur pour vérifier. – Bob

+0

Quelle est la déférence entre les mises à jour multi ou non? – vdrmrt

Répondre

1

Ted, Je crois que la cause de la lenteur peut être, à côté du fait que vous utilisez un curseur, que le tblAnswers complet est mis à jour chaque fois à travers le curseur. Je m'attends à ce qu'il y ait plusieurs lignes dans la table de réponse parce qu'un curseur a été utilisé pendant la conception. Tant que la décision n'est pas prise de passer d'un curseur à une op set-based, pensez-vous à ajouter une clause WHERE à la mise à jour de la table de réponses.

à mes answser

Si l'udf est cher alors j'ajouter une colonne à la table des questions ou créer une nouvelle table si modifing la table question n'est pas possible. Remplir la nouvelle colonne avec un drapeau pour "multi", avec le résultat de la fonction, en utilisant un déclencheur lorsque la question est insérée ou mise à jour.
Mettez à jour le tableau des réponses dans un sp en utilisant le code ci-dessous comme modèle. Appelez le SP avec l'ID de la question et la valeur du drapeau "multi".

update tblAnswers 
set col2 =1, 
col1 = CASE @isMulti THEN 1 Else AnswerID 
col3 = CASE @isMulti THEN (select count(*) from tblAnswers where [email protected]) ELSE (select LEN(count(*)) from tblAnswers where [email protected]) 
from tblQuestions 
inner join tblAnswers on tblQuestions.QuestionID= tblAnswers.QuestionID 
WHERE tblQuestions.QuestionID= @ID 
+0

^_^Merci. Il m'a fallu des heures pour réaliser cela. Ma procédure est beaucoup plus rapide (1:13 secondes) - elle est exécutée à <5 secondes, bien que je pense que l'utilisation d'une autre méthode pourrait réduire le temps total à <1 seconde. Je vais marquer cela comme la réponse de toute façon, car elle a résolu mon problème. – Bob

1

Je peut manquer quelque chose, mais pourquoi ne pas ce travail de peu en dehors du curseur si vous prenez la @QuestionId de la clause where ?:

 --check if @isMulti is true or not 
     if(@isMulti=1) 
     begin 
      update tblAnswers 
      set col1 = 1, col2 = 1, col3 = (select count(*) from tblAnswers where [email protected]) 
     end 
     else if(@isMulti=0) 
     begin 
      update tblAnswers 
      set col1 = AnswerID, col2 = 1, col3 = (select LEN(count(*)) from tblAnswers where [email protected]) 
     end 

EDIT

Sans le savoir plus sur les métadonnées Je ne suis pas sûr de la façon de traiter l'élément multi aux questions, mais cela devrait être un bon moyen de la réponse:

declare @question table (questionid int, multi int) 
declare @answer table (answerid int, col1 int, col2 int, col3 int) 

insert into @question (questionid, multi) values (1, 0) 
insert into @question (questionid, multi) values (2, 0) 
insert into @question (questionid, multi) values (3, 0) 
insert into @question (questionid, multi) values (4, 1) 
insert into @question (questionid, multi) values (5, 1) 


insert into @answer (answerid, col1, col2, col3) values (1, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (1, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (2, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (2, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (3, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (4, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (4, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (4, 0, 0, 0) 
insert into @answer (answerid, col1, col2, col3) values (5, 0, 0, 0) 

update @answer 
set col1 = 1, col2 = 1, col3 = (select count(*) from @answer a join @question q on a.answerid = q.questionid where q.multi = 0 and [@answer].answerid = a.answerid) 

select distinct * from @answer 
+0

Désolé, j'aurais été plus clair - pour chaque QuestionID je dois vérifier si cette question est multi ou non, donc le curseur en boucle à travers chaque question pour vérifier avant de vérifier que les réponses des questions. – Bob

+0

@Ted Mosbey - Je l'ai travaillé sans vraiment connaître vos données, mais il devrait vous donner un bon pointeur – amelvin

+0

Merci, bien que - basé sur la valeur multiple (qui est calculée dans un UDF) la col3 diffère. Si le nombre mulit col3 = select (*) autre col3 = select len ​​(count (*)) – Bob

0

Vous pouvez mettre à jour la table de réponses à travers une jointure, c'est-à-dire joindre des réponses à des questions sur l'ID, puis restreindre le @ID à l'aide d'une clause where.

+0

Cela ne me donne pas la possibilité de mettre à jour une valeur dans la table de réponse basée sur certains calculs dans le tableau de question. Si @ mulit = 1, answer.col3 = x, sinon answer.col3 = y. Ce n'est pas basé sur le questionID, mais le questionID est nécessaire pour calculer isMulti de cette question. – Bob