簡體   English   中英

如何改善存儲過程查詢

[英]how to improve stored procedure query

我已經存儲過程,針對MySql服務器檢查是否可以插入或更新記錄。 對於開始時間,它是如此之快,在5-10分鍾后,它是如此之慢..我運行了3000條記錄,而sp的執行是如此糟糕,在1-1.5小時后,它完成了...我想問,我該如何改善那??

謝謝。

存儲過程:

DELIMITER $$ 
DROP PROCEDURE IF EXISTS test.SPInsertUpdateCity$$ 
CREATE DEFINER=root@localhost PROCEDURE SPInsertUpdateCity( 
in SP_CityName VARCHAR(100) charset utf8, 
in SP_CitySynonyms mediumtext charset utf8, 
in SP_CityNumberPostOffice varchar(100), 
in SP_CityUpdatedDate date) 
BEGIN 
    if(not exists(select CityID from city where CityName = SP_CityName)) then 
        insert into city(CityName, CitySynonyms, CityNumberPostOffice ,UpdatedDate) 
        values(SP_CityName, CONCAT(',',SP_CitySynonyms, ','),SP_CityNumberPostOffice,SP_CityUpdatedDate);
    else if((exists(select cityId from city 
    where 
        CityName = SP_CityName and 
        (UpdatedDate < SP_CityUpdatedDate or UpdatedDate = SP_CityUpdatedDate))) and 
        not exists(SELECT CitySynonyms FROM city 
        WHERE 
            CitySynonyms in(select CitySynonyms from city where CitySynonyms like CONCAT('%,',SP_CitySynonyms,',%')))) 
            then 
            update city set 
                CitySynonyms = CONCAT(CitySynonyms,SP_CitySynonyms,','),
                UpdatedDate = SP_CityUpdatedDate; 
    end if; 
    end if; 
END$$ 
DELIMITER ; 

至少您可以使用UPSERT而不是檢查是否存在行,然后將其插入。

我通常使用MSSQL,但根據我的告訴您的elseif部分,這給您帶來了成功。 每次運行時,您要敲擊桌子3次,而可能是兩次。

這是重新格式化后的原始查詢,以方便比較。

    if(not exists(  select  CityID 
                    from    city 
                    where   CityName = SP_CityName)) then
        insert into city(   CityName, CitySynonyms, CityNumberPostOffice ,UpdatedDate) 
                values  (   SP_CityName, CONCAT(',',SP_CitySynonyms, ','), SP_CityNumberPostOffice, SP_CityUpdatedDate);
    else if((exists(    select  cityId 
                        from    city      
                        where   CityName = SP_CityName and 
                                (UpdatedDate < SP_CityUpdatedDate or UpdatedDate = SP_CityUpdatedDate))) and          
            not exists( SELECT CitySynonyms 
                        FROM city          
                        WHERE CitySynonyms in ( select CitySynonyms 
                                                from city 
                                                where CitySynonyms like CONCAT('%,',SP_CitySynonyms,',%')))) then
        update city set CitySynonyms = CONCAT(CitySynonyms,SP_CitySynonyms,','),                 
                        UpdatedDate = SP_CityUpdatedDate;      
    end if;      
    end if;  

這是新的

if(not exists(  select  CityID 
                from    city 
                where   CityName = SP_CityName)) then
    insert into city(   CityName, CitySynonyms, CityNumberPostOffice ,UpdatedDate) 
            values  (   SP_CityName, CONCAT(',',SP_CitySynonyms, ','), SP_CityNumberPostOffice, SP_CityUpdatedDate);
else if((exists(    select  cityId 
                    from    city      
                    where   CityName = SP_CityName and 
                            UpdatedDate <= SP_CityUpdatedDate)) and          
        not exists( select  CitySynonyms 
                    from    city 
                    where   CitySynonyms like CONCAT('%,',SP_CitySynonyms,',%'))) then
    update city set CitySynonyms = CONCAT(CitySynonyms,SP_CitySynonyms,','),                 
                    UpdatedDate = SP_CityUpdatedDate;      
end if;      
end if;  

還有其他一些事情可以做,因此可以進一步加快查詢速度。 like子句比equals慢得多。 如果可能,將諸如CONCAT('%,',SP_CitySynonyms,',%')之類CitySynonyms更改CitySynonyms = SP_CitySynonyms 假設您提供一個以“ D”開頭的同義詞,數據庫可以直接索引以查找D,甚至不查看其他記錄。 當然,要使其正常工作,您將需要在表上包含CitySynonyms列的索引。 如果使用Like子句,則數據庫將針對表中的每一行對該列運行instring()檢查,這在處理相當多的行時會嚴重影響性能。

從電話目錄的角度來看它,如果我想要一個姓史密斯的人,我會在書的背面查找索引,然后發現S在600頁的開頭(稱為“尋找”)。 我不在乎前599頁,甚至都不會看它們上的任何名稱。 沒有索引,我將不得不遍歷每一頁,直到找到以S開頭,SM開頭的名稱,依此類推(稱為掃描)。 但是LIKE子句就像搜索包含SMITH的姓氏,該姓氏可以是以下任何一項(來自Wiki的名稱)BlackSmith Coppersmith GoldSmith HammerSmith Smither Smithers等等。 如您所見,名字到處都是。 需要檢查每個名稱,以查看其是否包含SMITH。 它是您可以要求某人執行的最不可思議的事情之一,但是我們一直要求數據庫填充類似的內容,然后問為什么它很慢。 :)

另一件事是(UpdatedDate <SP_CityUpdatedDate或UpdatedDate = SP_CityUpdatedDate) ,我將其更改為UpdatedDate <= SP_CityUpdatedDate 真的需要這張支票嗎? 因為如果您不這樣做,則可以刪除整個if存在部分,因為您知道執行到該點時它就存在,因為如果有記錄,則返回的第一個if校驗將返回false。 因此,現在,else if在桌面上是一個命中,而不是三個。

if(not exists(  Select  CityID 
                from    city 
                where   CityName = SP_CityName)) then          

    insert into city(   CityName, CitySynonyms, CityNumberPostOffice ,UpdatedDate) 
            values  (   SP_CityName, CONCAT(',',SP_CitySynonyms, ','), SP_CityNumberPostOffice, SP_CityUpdatedDate);     

else if(not exists( select  CitySynonyms 
                    from    city 
                    where   CitySynonyms like CONCAT('%,',SP_CitySynonyms,',%'))) then              

    update city set CitySynonyms = CONCAT(CitySynonyms,SP_CitySynonyms,','),                 
                    UpdatedDate = SP_CityUpdatedDate;      
end if;      
end if;

編輯-為回應以下評論中的問題而添加。

在我進一步之前,應該

update city set CitySynonyms = CONCAT(CitySynonyms,SP_CitySynonyms,','), 
                UpdatedDate = SP_CityUpdatedDate;

update city set CitySynonyms = CONCAT(CitySynonyms,SP_CitySynonyms,','), 
                UpdatedDate = SP_CityUpdatedDate
where CityName = SP_CityName; 

因為目前,它為數據庫的每一行都添加了一個同義詞,因此我認為它應該僅更新您感興趣的那一行。

至於喜歡的說法。 我想我剛剛意識到發生了什么事。 如果我錯了糾正我。 CitySynonyms列是表中的大文本字段,其中多個值之間用逗號分隔,並且您正在嘗試使用like語句在該字符串中找到匹配項。

如果是這樣,是否可以稍微更改表結構? 這意味着將CitySynonyms列移動到第二個表中。

CREATE TABLE city ( CityID int(20) NOT NULL AUTO_INCREMENT, 
                    CityName varchar(100) NOT NULL, 
                    CityNumberPostOffice varchar(100) DEFAULT NULL, 
                    UpdatedDate date DEFAULT NULL, 
PRIMARY KEY (CityID) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE CitySynonym ( CitySynonymID int(20) NOT NULL AUTO_INCREMENT,
                           CityID int(20) NOT NULL ,                    
                           CitySynonym varchar(100) NOT NULL,
PRIMARY KEY (CitySynonymID) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

對於每個城市,您可以有多個同義詞。 它變得更加易於使用和維護,更不用說不再需要LIKE子句了。

Example:
City Table
CityID    CityName
1         Brisbane
2         Syndney

City Synonym Table
CitySynoymnID    CityID  Synonym
1                1       BNE
2                1       BRISSY
3                2       SYD

我想指出的是,每當在字段中有逗號分隔的列表時,就需要重構數據庫以具有相關表。 在傾斜的字段上搜索或嘗試更新字段永遠都無法獲得良好的性能。 數據庫設計的第一個規則是永遠不要在一個字段中保存多個信息。 使用子表來保存信息,您將在所有內容上獲得更快的性能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM