2010-11-22 6 views
0

私は、処理が必要な状況があり、最後に誘惑可能なレコードをデータベーステーブルに挿入する必要があります。各挿入の前に、条件が満たされていることを確認し、各挿入の直後に、データベースの2番目のテーブルを更新する必要があります。私の問題は、現在、クエリを実行するのに約25分かかり、私のアプリケーションがより敏感になるように大幅に時間を短縮したいと思っています。どうしたらいいですか?T-SQL Insert-temptable、CTEs、WHILEループの最適化

DECLARE @rowcounter as INTEGER 


        CREATE TABLE #temporary_phonetable 
        (
          rownumber int not null identity(1,1), 
          record_no BIGINT, 
          phone_name BIGINT, 
          phone_number Varchar(25) not null , 
          responsemessage Varchar(200) not null , 
          messagepriority Varchar(14) not null , 
          phone_id BIGINT, 
          AD_show BIGINT, 
          power_show Varchar(400), 
          service_provider VARCHAR(30), 
          Phone_flag VARCHAR(30), 
          questionMessage BIGINT, 
          PRIMARY KEY (phone_id, phone_number, rownumber) 
         ,UNIQUE (questionMessage, record_no, rownumber) 
        ) 
        --GET PHONE DATA 
           --if phone numbers are sent in from the client, then we want to process those instead 
      IF (((@listofphones IS NULL OR LEN(@listofphones) <1) AND LEN(@peoplegroups) >0) ) 
      BEGIN 
        --NO PHONENUMBER BUT THERE ARE GROUPS AVAILABLE       
           INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show, responsemessage) 
           SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE @includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + @responsemessages 
             ELSE @responsemessages END as text_message 
           FROM user u WITH(NOLOCK) 
           INNER JOIN Phonenumbers n WITH(NOLOCK) ON n.user_no = u.user_no 
           INNER JOIN PeopleGroupRelations g ON g.phone_id=n.phone_id 
           INNER JOIN (Select items FROM Split(@peoplegroups, @listofphonesdelimiter)) gg ON g.group_no = gg.items 
           WHERE [email protected] 
           AND n.status=''active'' 
           SET @rowcounter = @@ROWCOUNT 
      END 
      ELSE IF (LEN(@listofphones) >1 AND LEN(@peoplegroups) >0) 
       BEGIN 
         --PHONENUMBER AND GROUPS 
           INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show, responsemessage) 
           SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE @includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + @responsemessages 
             ELSE @responsemessages END as text_message 
           FROM Split(@listofphones, ''|'') s 
           INNER JOIN PhoneNumbers n WITH(NOLOCK) ON n.phone_number = s.items 
           INNER JOIN User u WITH(NOLOCK) ON n.user_no =u.user_no 
           INNER JOIN PeoplegroupRelations g ON g.phone_id=n.phone_id 
           INNER JOIN (Select items FROM Split(@peoplegroups, @listofphonesdelimiter)) gg ON g.group_no = gg.items 
           WHERE [email protected] 
           AND n.status=''active'' 
           SET @rowcounter = @@ROWCOUNT 
      END 
       ELSE IF (LEN(@listofphones) >1 AND LEN(@peoplegroups) >0) 
       BEGIN 
         --PHONENUMBER AND NO GROUPS 
           INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show, responsemessage) 
           SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE @includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + @responsemessages 
             ELSE @responsemessages END as text_message 
           FROM Split(@listofphones, ''|'') s 
           INNER JOIN PhoneNumbers n WITH(NOLOCK) ON n.phone_number = s.items 
           INNER JOIN User u WITH(NOLOCK) ON n.user_no =u.user_no 
           INNER JOIN PeopleGroupRelations g ON g.phone_id=n.phone_id 
           INNER JOIN (Select items FROM Split(@peoplegroups, @listofphonesdelimiter)) gg ON g.group_no = gg.items 
           WHERE [email protected] 
           AND n.status=''active'' 
           SET @rowcounter = @@ROWCOUNT 
      END 
      ELSE 
        BEGIN 
          -- NO PHONENUMBER NO GROUP --- IE. SEND TO ALL PHONE NUMBERS 
           INSERT INTO #temporary_phonetable(phone_name, phone_number, messagepriority, phone_id, AD_show, power_show,responsemessage) 
           SELECT n.phone_name, n.phone_number,u.messagepriority, n.phone_id , u.AD_show, u.power_show , CASE @includegreetings WHEN 1 THEN LTRIM(RTRIM(phone_name)) + @responsemessages 
             ELSE @responsemessages END as text_message 
           FROM User u 
              INNER JOIN PhoneNumbers n ON n.user_no = u.user_no 
           WHERE 
             n.status=''active'' 
             AND [email protected] 
            SET @rowcounter = @@ROWCOUNT 
        END 



        IF(@rowcounter>0) 
        BEGIN 
            DECLARE @service_provider as Varchar(30) 
            DECLARE @PhoneType as Varchar(30) 

            IF (LOWER(RTRIM(LTRIM(@sendresponseswhen))) ='now') 
            BEGIN 
               SET @dateresponsessent = GETDATE() 
            END 

                 DECLARE @rownumber int 
                 DECLARE @power_show BIT 
                 DECLARE @AD_show BIT 
                 set @rownumber = 0 
                 WHILE @rownumber < @rowcounter 
                 BEGIN 
                    set @rownumber = @rownumber + 1 
                    -- THE VARIABLES 
                       DECLARE @record_no as BIGINT 
                       DECLARE @phone_name VARCHAR(30) 
                       DECLARE @messagepriority as INTEGER 
                       DECLARE @phone_number VARCHAR(30) 
                       DECLARE @phone_id BIGINT 
                       DECLARE @questionMessage BIGINT 

                    SELECT 
                       @phone_name = n.phone_name, @phone_number =n.phone_number, @messagepriority =n.messagepriority, @phone_id=n.phone_id , 
                       @AD_show=n.AD_show, @power_show=n.power_show 
                     FROM 
                       #temporary_phonetable n WITH(NOLOCK) 
                     WHERE n.rownumber = @rownumber 

                     SET @record_no = AddMessageToQueue(@phone_number, @responsemessages, @dateresponsessent, @savednames, @userid, un.messagepriority, @responsetype, 
                     un.AD_show, un.power_show, @service_provider, @PhoneType) 


                     If(@questionid > 0) 
                     BEGIN 
                       SET @questionMessage = AddQuestionMessage(@questionid,@phone_id, @record_no, DATEADD(d, 30, GETDATE())) 
                     END 


               UPDATE #temporary_phonetable SET record_no = @record_no, [email protected] WHERE phone_number = @phone_number AND rownumber = @rownumber 
            END 
            IF(@power_show >0) 
            BEGIN 
              SET @responsemessages = @responsemessages + dbo.returnPoweredBy() 
            END 
            IF(@AD_show > 0) 
            BEGIN 
              SELECT @responsemessages = @responsemessages + CASE 
                              WHEN (LEN(@responsemessages) + 14)< 160 THEN dbo.returnAD(@responsemessages) 
                              ELSE '''' END 
            END 


            RETURN @rowcounter 
         END 

私はこれが問題の大部分が存在する場所だと考えています。

@rowcounterセット@rownumberをBEGIN < @rownumber

WHILE = @rownumber + 1 - 変数がINTEGER DECLAREの@phone_numberとしてBIGINT DECLAREの@phone_name VARCHAR(30) DECLAREの@messagepriorityとして@record_no DECLARE VARCHAR(30) DECLARE @phone_id BIGINT DECLARE @questionMessage BIGINT

                SELECT 
                      @phone_name = n.phone_name, @phone_number =n.phone_number, @messagepriority =n.messagepriority, @phone_id=n.phone_id , 
                      @AD_show=n.AD_show, @power_show=n.power_show 
                    FROM 
                      #temporary_phonetable n WITH(NOLOCK) 
                    WHERE n.rownumber = @rownumber 

                    SET @record_no = AddMessageToQueue(@phone_number, @responsemessages, @dateresponsessent, @savednames, @userid, un.messagepriority, @responsetype, 
                    un.AD_show, un.power_show, @service_provider, @PhoneType) 


                    If(@questionid > 0) 
                    BEGIN 
                      SET @questionMessage = AddQuestionMessage(@questionid,@phone_id, @record_no, DATEADD(d, 30, GETDATE())) 
                    END 


              UPDATE #temporary_phonetable SET record_no = @record_no, [email protected] WHERE phone_number = @phone_number AND rownumber = @rownumber 
           END 
+0

あなたの(長い)投稿されたコードで何が減速の原因となっているかを特定し、私たちが助けることができるかもしれません。 –

+0

低速はWHILE LOOPから始まります。その直前に、コードは約0.16秒実行されます。 Whileループに当たったら、処理時間が25分増加します – Kobojunkie

答えて

0

一時テーブルのrownumberにユニーク制約を追加します。 WHILECTEと書き換えてください。関数を呼び出すには、APPLYを使用します。

+0

これはカウントされませんか?ユニーク(questionMessage、record_no、rownumber)。それとも、これはあなたが意味するものではありませんか? – Kobojunkie

+0

本当にありません。あなたはこれを本当に速くしたいと思います:どこにn.rownumber = @rownumber。このフィールドのユニークな制約またはインデックスは、不思議を行うことができます。本当にパフォーマンスが必要なのは、ループを取り除くことです。 –

+0

また、AddMessageToQueueとAddQuestionQueueは、関数ではなくSTOREDPROCSであることを追加します。 – Kobojunkie

0

また、テンポラリテーブルではなくテーブル変数の使用を検討することもできます。あなたはtempdbに書き込むことはなく、テーブル変数はメモリに作成されるので速くなります。

This articleは素晴らしい比較をしています。

+0

私はこれを試しましたが、違いはまだありません。他の提案はどうぞ? – Kobojunkie

+0

テーブル変数に対して行ごとにループチェックを行う代わりに、条件を満たすデータベースをINSERT..SELECTすることができます。条件を満たしていない行があるかどうかを知る必要がある場合は、条件を逆にしてそれを見つけることができます。 – RLT

+0

クエリループを見ると、実際には各行のストアドプロシージャを実行しなければならないので、ループがあるのです。私は、INSERTを使って行ごとに実行できないことを知っています。 。 。 。それとも、できますか? – Kobojunkie