[英]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.