我有存储过程,如果可以插入或更新记录,则检查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 ;
答案 0 :(得分:0)
至少你可以使用UPSERT而不是检查行的存在然后插入它。
答案 1 :(得分:0)
我通常使用MSSQL,但是从我可以告诉你的其他部分给你的命中。每当它运行两次时你就会击中它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慢得多。如果可能,将 CitySynonyms更改为 CitySynonyms = SP_CitySynonyms ,将CONCAT('%,',SP_CitySynonyms,',%')等CitySynonyms更改为。 假设您提供以“D”开头的同义词,数据库可以索引直接搜索到D,甚至不会查看其他记录。 当然,要使用它,您需要在表格上包含CitySynonyms列的索引。如果使用Like子句,数据库将运行instring()检查 针对表中每一行的列,这是处理相当多行时的主要性能。
从电话目录的角度来看,如果我想要一个名字叫史密斯的人,我会在书的后面查找索引,并发现S在第600页开始(称为搜索)。我不关心前599页,甚至不看任何名字。如果没有索引,我将不得不遍历每一页,直到我从S开始,然后是SM,等等(称为扫描)。但LIKE子句就像搜索包含SMITH的姓氏一样,该姓氏可能是以下任何一个(来自Wiki的名字)BlackSmith Coppersmith GoldSmith HammerSmith Smither Smithers等。正如您所看到的那样,名字遍布各处。需要检查每个名称以查看它是否包含SMITH。它是你可以要求别人做的最不酷的事情之一,但我们要求数据库一直这样,然后问为什么它很慢。 :)
另一件事是(UpdatedDate&lt; SP_CityUpdatedDate或UpdatedDate = SP_CityUpdatedDate),我已将其更改为 UpdatedDate&lt; = SP_CityUpdatedDate 。 真的需要检查吗?因为如果你不这样做,你可以删除整个if exists部分因为你知道它存在,如果执行到达那个点,那么因为记录存在而返回false的第一个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
答案 2 :(得分:0)
我想指出的是,只要在字段中有逗号分隔列表,就需要重构数据库以改为使用相关表。您永远无法在分隔字段上搜索或尝试更新字段。数据库设计的最初规则之一是永远不会在一个字段中保存多条信息。对于包含子表的所有内容,您将获得更快的性能来保存信息。