实战:上亿数据如何秒查
作者:网络转载 发布时间:[ 2015/4/14 12:49:09 ] 推荐标签:数据库 秒查 SQL
一.对原SQL语句的分析
1.查询语句的where条件,有大量@var in…or(@var=”)的片段
2.where条件有like‘%’+@var+’%’
3.where条件有case…end函数
4.多次连接同一表查询,另外使用本身已嵌套的视图表,是不是必须,是否可替代?
5.SQL语句有*号,视图中也有*号出现
二.优化设计
首先是用存储过程改写,好处是设计灵活。
核心思想是:用一个或多个查询条件(查询条件要求至少输入一个)得到临时表,每个查询条件如果查到集合,更新这张临时表,后汇总的时候,只需判断这个临时表是否有值。以此类推,可以建立多个临时表,将查询条件汇总。

这样做目前来看至少两点好处:
1.省去了对变量进行=@var or(@var=”)的判断;
2.抛弃sql拼接,提高代码可读性。
再有是在书写存储过程,这个过程中要注意:
1.尽量想办法使用临时表扫描替代全表扫描;
2.抛弃in和not in语句,使用exists和not exists替代;
3.和客户确认,模糊查询是否有必要,如没有必要,去掉like语句;
4.注意建立适当的,符合场景的索引;
5.踩死“*”号;
6.避免在where条件中对字段进行函数操作;
7.对实时性要求不高的报表,允许脏读(with(nolock))。
三.存储过程
如果想参考优化设计片段的详细内容,请参阅SQL代码:
/**
*某某跟踪报表
**/
--exec spName1'','','','','','','公司代号'
CREATE Procedure spName1
@MESOrderID nvarchar(320),--工单号,多30个
@LotName nvarchar(700),--产品序列号,多50个
@DateCode nvarchar(500),--供应商批次号,多30个
@BatchID nvarchar(700),--组装件序列号/物料批号,多50个
@comdef nvarchar(700),--组装件物料编码,多30个
@SNCust nvarchar(1600),--外部序列号,多50个
@OnPlant nvarchar(20)--平台
AS
BEGIN
SET NOCOUNT ON;
/**
*1)定义全局的临时表,先根据六个查询条件的任意一个,得出临时表结果
**/
CREATE TABLE#FinalLotName
(
LotName NVARCHAR(50),--序列号
SourceLotName NVARCHAR(50),--来源序列号
SNCust NVARCHAR(128)--外部序列号
)
--1.1
IF@LotName<>''
BEGIN
SELECT Val INTO#WorkLot FROM fn_String_To_Table(@LotName,',',1)
SELECT LotPK,LotName INTO#WorkLotPK FROM MMLots WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#WorkLot b WHERE b.Val=MMLots.LotID)
--求SourceLotPK只能在这里求
SELECT a.LotPK,a.SourceLotPK into#WorkSourcePK FROM MMLotOperations a WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#WorkLotPK b WHERE b.LotPK=a.LotPK)AND a.SourceLotPK IS NOT NULL
SELECT a.LotPK,a.SourceLotPK,b.LotName INTO#WorkSourcePK2 FROM#WorkSourcePK a JOIN#WorkLotPK b ON a.LotPK=b.LotPK
INSERT INTO#FinalLotName SELECT a.LotName,b.LotName AS SourceLotName,NULL FROM#WorkSourcePK2 a JOIN(SELECT LotPK,LotName FROM MMLots WITH(NOLOCK))b on a.SourceLotPK=b.LotPK--b的里面加不加WHERE RowDeleted=0待确定
SELECT a.LotName,a.SourceLotName,b.SNCust INTO#FinalLotNameX1 FROM#FinalLotName a LEFT JOIN CO_SN_LINK_CUSTOMER b WITH(NOLOCK)ON a.LotName=b.SNMes
DELETE FROM#FinalLotName
INSERT INTO#FinalLotName SELECT LotName,SourceLotName,SNCust FROM#FinalLotNameX1
END
--1.2
IF@BatchID<>''
BEGIN
SELECT Val INTO#WorkSourceLot FROM fn_String_To_Table(@BatchID,',',1)
IF EXISTS(SELECT 1 FROM#FinalLotName)--如果@LotName也不为空
BEGIN
SELECT a.LotName,a.SourceLotName,a.SNCust INTO#FinalLotNameX2 FROM#FinalLotName a WHERE EXISTS(SELECT 1 FROM#WorkSourceLot b WHERE a.SourceLotName=b.Val)
DELETE FROM#FinalLotName
INSERT INTO#FinalLotName SELECT LotName,SourceLotName,SNCust FROM#FinalLotNameX2
END
ELSE--@LotName条件为空
BEGIN
SELECT LotPK AS SourceLotPK,LotName AS SourceLotName INTO#2 FROM MMLots WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#WorkSourceLot b WHERE b.Val=MMLots.LotID)
SELECT a.LotPK,a.SourceLotPK into#21 FROM MMLotOperations a WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#2 b WHERE b.SourceLotPK=a.SourceLotPK)
SELECT a.LotPK,a.SourceLotPK,b.SourceLotName INTO#22 FROM#21 a JOIN#2 b ON a.SourceLotPK=b.SourceLotPK
INSERT INTO#FinalLotName SELECT b.LotName,a.SourceLotName,NULL FROM#22 a JOIN(SELECT LotPK,LotName FROM MMLots WITH(NOLOCK))b on a.LotPK=b.LotPK--b的里面加不加WHERE RowDeleted=0待确定
SELECT a.LotName,a.SourceLotName,b.SNCust INTO#FinalLotNameX21 FROM#FinalLotName a LEFT JOIN CO_SN_LINK_CUSTOMER b WITH(NOLOCK)ON a.LotName=b.SNMes
DELETE FROM#FinalLotName
INSERT INTO#FinalLotName SELECT LotName,SourceLotName,SNCust FROM#FinalLotNameX21
END
END
--1.3
IF@SNCust<>''
BEGIN
SELECT Val INTO#WorkCustomSN FROM fn_String_To_Table(@SNCust,',',1)
IF EXISTS(SELECT 1 FROM#FinalLotName)--前面两个条件至少有一个有值
BEGIN
SELECT a.LotName,a.SourceLotName,a.SNCust INTO#FinalLotNameX3 FROM#FinalLotName a WHERE EXISTS(SELECT 1 FROM#WorkCustomSN b WHERE a.SNCust=b.Val)
DELETE FROM#FinalLotName
INSERT INTO#FinalLotName SELECT LotName,SourceLotName,SNCust FROM#FinalLotNameX3
END
ELSE
BEGIN
SELECT a.SNMes INTO#WorkLotX FROM CO_SN_LINK_CUSTOMER a WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#WorkCustomSN b WHERE a.SNCust=b.Val)
-------------------以下逻辑和变量1(@LotName)类似[先根据外部序列号求解序列号,再照搬第一个判断变量的方式]
SELECT LotPK,LotName INTO#WorkLotPKX FROM MMLots WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#WorkLotX b WHERE b.SNMes=MMLots.LotID)
--求SourceLotPK只能在这里求
SELECT a.LotPK,a.SourceLotPK into#WorkSourcePKX FROM MMLotOperations a WITH(NOLOCK)WHERE EXISTS(SELECT 1 FROM#WorkLotPKX b WHERE b.LotPK=a.LotPK)AND a.SourceLotPK IS NOT NULL
SELECT a.LotPK,a.SourceLotPK,b.LotName INTO#WorkSourcePK2X FROM#WorkSourcePKX a JOIN#WorkLotPKX b ON a.LotPK=b.LotPK
INSERT INTO#FinalLotName SELECT a.LotName,b.LotName AS SourceLotName,NULL FROM#WorkSourcePK2X a JOIN(SELECT LotPK,LotName FROM MMLots WITH(NOLOCK))b on a.SourceLotPK=b.LotPK--b的里面加不加WHERE RowDeleted=0待确定
SELECT a.LotName,a.SourceLotName,b.SNCust INTO#FinalLotNameX31 FROM#FinalLotName a LEFT JOIN CO_SN_LINK_CUSTOMER b WITH(NOLOCK)ON a.LotName=b.SNMes
DELETE FROM#FinalLotName
INSERT INTO#FinalLotName SELECT LotName,SourceLotName,SNCust FROM#FinalLotNameX31
-----------------------
END
END
/**
*2)定义全局的临时表,用于替换第一个全局临时表。
**/
CREATE TABLE#FinalCO_SN
(
SN NVARCHAR(50),
SourceSN NVARCHAR(50),
SNCust NVARCHAR(128),
matl_def_id NVARCHAR(50),--sn的物料ID
ComMaterials NVARCHAR(50),--SourceSN的物料ID
MESOrderID NVARCHAR(20),
OnPlantID NVARCHAR(20),
VendorID NVARCHAR(20),
DateCode NVARCHAR(20),
SNNote NVARCHAR(512)
)
--2.1
IF@MESOrderID<>''
BEGIN
-------------------------------将MESOrderID做特殊处理-----------------------------------
SELECT Val INTO#WorkMESOrderID FROM fn_String_To_Table(@MESOrderID,',',1)
IF@OnPlant='Comba'
BEGIN
UPDATE#WorkMESOrderID SET Val='C000'+Val WHERE LEN(Val)=9
END
ELSE
BEGIN
UPDATE#WorkMESOrderID SET Val='W000'+Val WHERE LEN(Val)=9
END
SELECT SN,MaterialID,MESOrderID,OnPlantID INTO#WorkCO_SN1 FROM CO_SN_GENERATION a WITH(NOLOCK)
WHERE SNType='IntSN'AND SNRuleName='ProductSNRule'AND OnPlantID=@OnPlant
AND EXISTS(SELECT 1 FROM#WorkMESOrderID b WHERE a.MESOrderID=b.Val)
------------------------------------------------------------------------------------------

sales@spasvo.com