简体   繁体   中英

How can I make this SQL script run faster?

I wrote the script to do some fixing for the values in the tables. But it takes forever to finish.. actually never saw it finished.. just hanging there.. any point how to optimize it will be appreciated.

There are 2 tables: FundCorrespondencePreference which can have some of the IDContacts columns checked in the records. If they are checked, the appropriate records are supposed to be present in ContentManagementRights table (with almost identical fields except some).

The idea is to go through ContentManagemtnRights and find all the unique records combining 4 columns, pick some of the columns values and and collect all the users from FundCorrespondencePreference table , then check if that user is checked in that collection, go back to ContentManagementRights table and check if such record is present, if not, insert a record with corresponding values in the columns.

Hope I explained it more or less coherently. Any way, appreciate your time and suggestions. Here goes the script:

--the script will check if any of the contacts for a partner in FundCorrespondencePreferences are missing in ContentManagementRight table
-- some of the contacts in FundCorrespondencePreference just not appear in ContentManagementRight as checked

    declare @IDFundInfo char(30)
    declare @IDCompany char(30)
    declare @IDFundTransactionParameter char(30)
    declare @IDContentManagement char(30)
    declare @IDUserInfo char(30)
    declare @ID char(30)

    declare @curContentManagementRights cursor
    set @curContentManagementRights = cursor fast_forward for
    --first select distinct records from ContentManagementRights for IDFundInfo, IDCompany,IDFundTransactionParameter and IDContentManagement where
    --bFundLevelAccess == 0
    SELECT distinct
       ContentManagementRights.IDFundInfo, 
       ContentManagementRights.IDCompany, 
       ContentManagementRights.IDFundTransactionParameter, 
       ContentManagementRights.IDContentManagement
    FROM ContentManagementRights 
    WHERE     
       (ContentManagementRights.bFundLevelAccess = 0)
    ORDER BY 
       idfundinfo, idcompany,idfundtransactionparameter, idcontentmanagement

    open @curContentManagementRights;
    fetch from @curContentManagementRights into @IDFundInfo, @IDCompany,@IDFundTransactionParameter,@IDContentManagement

    WHKLE @@fetch_status = 0
    BEGIN
        --get all IDContactInfo for the chosen fund, partnerid,fundtranactionparameterid from fundcorrespondencepreference table + make sure that at least one correspTO parameter

       declare @curFundCorrespondencePreference cursor
       set @curFundCorrespondencePreference = cursor fast_forward for 
         SELECT     
             UserInfo.IDUserInfo
         FROM         
             FundCorrespondencePreference 
         INNER JOIN
             FundTransactionParameter ON FundCorrespondencePreference.IDFundTransactionParameter = FundTransactionParameter.IDFundTransactionParameter 
         INNER JOIN
             ContactInfo ON FundCorrespondencePreference.IDContactInfo = ContactInfo.IDContactInfo 
         INNER JOIN
             UserInfo ON ContactInfo.IDContactInfo = UserInfo.IDContactInfo 
         INNER JOIN
             UserGroupInfo ON UserInfo.IDUserInfo = UserGroupInfo.IDUserInfo 
         INNER JOIN
             GroupInfo ON UserGroupInfo.IDGroupInfo = GroupInfo.IDGroupInfo
         WHERE     
            (FundTransactionParameter.IDFundInfo = @IDFundInfo) 
            AND (FundCorrespondencePreference.IDCompany = @IDCompany) 
            AND (FundCorrespondencePreference.IDFundTransactionParameter = @IDFundTransactionParameter) 
            AND (FundCorrespondencePreference.bEmail = 1) 
            AND (GroupInfo.sName = N'Xtranet Partner Group') 
            OR (FundCorrespondencePreference.bFax = 1) 
            OR (FundCorrespondencePreference.bLetterTo = 1) 
            OR (FundCorrespondencePreference.bLetterCc = 1) 
            OR (FundCorrespondencePreference.bEmailCc = 1) 
            OR (FundCorrespondencePreference.bFaxCc = 1)

          --go through all the contacts chosen from FundCorrespondencePreference table and 
          --if not present in ContentManagementRight table, insert into the table record with previously selected parameters
          open @curFundCorrespondencePreference;
          fetch from @curFundCorrespondencePreference into @IDUserInfo

          WHILE @@fetch_status = 0
          BEGIN
            if 
               (Select Count(IDContentManagementRights) 
                from ContentManagementRights 
                where 
                   IDContentManagement = @IDContentManagement 
                   and IDFundInfo = @IDFundInfo 
                   and IDCompany = @IDCompany 
                   and IDUserInfo = @IDUserInfo) = 0
             begin
            --insert a new record in ContentManagementRights if there is none for chosen parameters
            Exec GetNextID 'ContentManagementRights', @ID output
            INSERT INTO ContentManagementRights (IDContentManagementRights,IDContentManagement,IDFundInfo,IDCompany,sCreatedBy,dtCreatedDate,sUpdatedBy,dtUpdatedDate,IDUserInfo,IDFundTransactionParameter,bFundLevelAccess)
            VALUES (@ID,@IDContentManagement,@IDFundInfo,@IDCompany,'admin',GETDATE(),'admin',GETDATE(),@IDUserInfo,@IDFundTransactionParameter,0)          
              end
         end
        close @curFundCorrespondencePreference;
        deallocate @curFundCorrespondencePreference;
    --      
        end

    close @curContentManagementRights;
    deallocate @curContentManagementRights;

i dont think many people gonna read that very long query. the logic is redundant.

for instance if(select count(something) = 0) u can replace with having clause and eliminate extra use of nested cursor.

the code below is just guideline. i didn't put 'group by' before having clause in the code. hope it helps.

my tip is, SQL is made data manipulating language. not individual object manupulate like OOP programming. i'm saying this becus u try to use cursor to handle each row which is OOP programming style eg. for loop to do work in each row. but sql intend to work on multiple row at a time. try use aggregate, case when instead

   declare @IDFundInfo char(30)
    declare @IDCompany char(30)
    declare @IDFundTransactionParameter char(30)
    declare @IDContentManagement char(30)
    declare @IDUserInfo char(30)
    declare @ID char(30)

    declare @curContentManagementRights cursor
    set @curContentManagementRights = cursor fast_forward for
    --first select distinct records from ContentManagementRights for IDFundInfo, IDCompany,IDFundTransactionParameter and IDContentManagement where
    --bFundLevelAccess == 0
    SELECT distinct
       ContentManagementRights.IDFundInfo, 
       ContentManagementRights.IDCompany, 
       ContentManagementRights.IDFundTransactionParameter, 
       ContentManagementRights.IDContentManagement
    FROM ContentManagementRights 
    WHERE     
       (ContentManagementRights.bFundLevelAccess = 0)
    ORDER BY 
       idfundinfo, idcompany,idfundtransactionparameter, idcontentmanagement

    open @curContentManagementRights;
    fetch from @curContentManagementRights into @IDFundInfo, @IDCompany,@IDFundTransactionParameter,@IDContentManagement

    WHKLE @@fetch_status = 0
    BEGIN
        --get all IDContactInfo for the chosen fund, partnerid,fundtranactionparameterid from fundcorrespondencepreference table + make sure that at least one correspTO parameter

     INSERT INTO ContentManagementRights (IDContentManagementRights,IDContentManagement,IDFundInfo,IDCompany,sCreatedBy,dtCreatedDate,sUpdatedBy,dtUpdatedDate,IDUserInfo,IDFundTransactionParameter,bFundLevelAccess)
         SELECT     
             @ID,@IDContentManagement,@IDFundInfo,@IDCompany,'admin',GETDATE(),'admin',GETDATE(),UserInfo.IDUserInfo,@IDFundTransactionParameter,0
         FROM         
             FundCorrespondencePreference 
         INNER JOIN
             FundTransactionParameter ON FundCorrespondencePreference.IDFundTransactionParameter = FundTransactionParameter.IDFundTransactionParameter 
         INNER JOIN
             ContactInfo ON FundCorrespondencePreference.IDContactInfo = ContactInfo.IDContactInfo 
         INNER JOIN
             UserInfo ON ContactInfo.IDContactInfo = UserInfo.IDContactInfo 
         INNER JOIN
             UserGroupInfo ON UserInfo.IDUserInfo = UserGroupInfo.IDUserInfo 
         INNER JOIN
             GroupInfo ON UserGroupInfo.IDGroupInfo = GroupInfo.IDGroupInfo
         WHERE     
            (FundTransactionParameter.IDFundInfo = @IDFundInfo) 
            AND (FundCorrespondencePreference.IDCompany = @IDCompany) 
            AND (FundCorrespondencePreference.IDFundTransactionParameter = @IDFundTransactionParameter) 
            AND (FundCorrespondencePreference.bEmail = 1) 
            AND (GroupInfo.sName = N'Xtranet Partner Group') 
            OR (FundCorrespondencePreference.bFax = 1) 
            OR (FundCorrespondencePreference.bLetterTo = 1) 
            OR (FundCorrespondencePreference.bLetterCc = 1) 
            OR (FundCorrespondencePreference.bEmailCc = 1) 
            OR (FundCorrespondencePreference.bFaxCc = 1)

    having count(IDContentManagementRights) = 0

        end

    close @curContentManagementRights;
    deallocate @curContentManagementRights;

Sir or madam, you did very well by refusing to wait till the script finished its job. With two cursors here, neither one is being scrolled beyond its first row. The script would indeed take forever to finish. (Well, as long as the system could be kept working, anyway.)

You really need to put inside each loop (typically, immediately before the end of the loop) their associative fetch from... instructions, identical to the ones before each loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM