单列表变量与字符串拆分的对照(SqlServer)

  最近遇到一个问题,在SQLServer中,需要根据用户传入的一系列ID值更新对应的记录。有两种方法,一种是将这些ID值使用逗号分隔,拼接成字符串传入,一种是以表变量的方式传入。最开始,我想当然的认为传入表变量要比传入字符串再拆分效果要好,结果发现并没有这么简单。

  1、传入字符串再拆分

declare @list varchar(max)
set @list='20008,20021,20038,20048,20081,20105,20106,20117,20142,20151,20157,20166,20171,20172,20179,20181,20194,20208,20210,20213,20224,20245,20268,20294,20308,20310,20344,20354,20364,20365,20366,20379,20386,20393,20395,20459,20487,20488,20489,20498,20499,20509,20526,20533,20534,20536,20540,20543,20544,20554,20578,20586,20595,20602,20609,20623,20627,20638,20667,20669,20676,20681,20697,20715,20725,20736,20740,20753,20775,20782,20789,20805,20815,20824,20825,20835,20849,20860,20863,20869,20872,20878,20891,20892,20901,20914,20920,20955,20968,20976,20993,20995,21011,21018,21056,21061,21062,21091,21095,21100,21109,21122,21143,21168,21195,21196,21199,21206,21213,21231,21232,21234,21242,21262,21278,21330,21334,21336,21343,21357,21358,21363,21375,21381,21382,21386,21390,21430,21434,21465,21479,21493,21494,21497,21503,21518,21519,21523,21528,21548,21553,21559,21567,21575,21593,21598,21601,21637,21653,21670,21674,21675,21718,21733,21734,21738,21742,21750,21755,21759,21761,21762,21766,21768,21778,21779,21789,21797,21798,21806,21817,21822,21832,21845,21848,21849,21850,21851,21857,21868,21875,21895,21896,21905,21936,21939,21947,21954,21955,21977,21978,21989,22007,22026,22057,22061,22070,22077,22110,22111,22122,22141,22158,22159,22163,22183,22187,22189,22194,22208,22210,22226,22234,22261,22262,22272,22273,22300,22359,22361,22367,22370,22408,22415,22422,22433,22436,22437,22462,22482,22484,22494,22508,22515,22552,22573,22653,22662,22663,22672,22675,22676,22694,22731,22754,22760,22768,22769,22842,22851,22855,22858,22876,22882,22883,22888,22889,22896,22898,22899,22907,22935,22949,22950,22951,22952,22983,22996,23001,23003,23028,23029,23032,23033,23037,23039,23040,23046,23049,23054,23062,23064,23069,23070,23077,23098,23107,23122,23123,23148,23150,23151,23197,23205,23212,23241,23242,23265,23266,23279,23280,23283,23300,23319,23320,23330,23358,23368,23371,23382,23390,23406,23422,23431,23436,23465,23471,23472,23474,23475,23480,23485,23504,23510,23517,23519,23528,23534,23543,23571,23573,23625,23656,23657,23662,23668,23680,23689,23693,23694,23699,23704,23709,23724,23755,23757,23770,23776,23781,23817,23824,23837,23843,23862,23881,23888,23893,23907,23909,23920,23942,23966,24004,24069,24070,24117,24129,24136,24143,24146,24156,24182,24192,24202,24203,24208,24210,24213,24217,24224,24225,24227,24242,24266,24272,24304,24306,24312,24322,24391,24407,24408,24448,24454,24491,24498,24505,24506,24510,24516,24531,24536,24543,24546,24553,24554,24570,24572,24575,24580,24581,24585,24591,24602,24617,24620,24634,24649,24656,24675,24680,24691,24703,24710,24711,24718,24723,24726,24741,24782,24821,24822,24826,24827,24840,24868,24869,24871,24893,24894,24912,24925,24962,24963,24989,24992,24999,25000,25004,25008,25016,25022,25024,25026,25030,25036,25048,25059,25062,25070,25076,25078,25089,25091,25099,25102,25111,25115,25116,25136,25137,25147,25152,25168,25181,25194,25197,25205,25206,25207,25214,25215,25218,25220,25234,25267,25281,25283,25321,25322,25329,25331,25335,25394,25395,25416,25417,25421,25478,25479,25494,25502,25503,25505,25538,25550,25575,25583,25584,25628,25663,25664,25665,25667,25686,25695,25699,25705,25718,25740,25746,25763,25770,25774,25797,25809,25814,25818,25822,25823,25838,25842,25856,25861,25863,25879,25882,25883,25897,25899,25914,25916,25919,25943,25955,25964,25976,25982,25985,26000,26002,26005,26019,26027,26028,26030,26031,26032,26048,26053,26056,26063,26070,26082,26090,26093,26100,26116,26120,26128,26129,26142,26148,26157,26193,26204,26216,26225,26288,26294,26297,26301,26332,26339,26342,26349,26368,26369,26380,26396,26411,26436,26437,26438,26439,26446,26469,26474,26482,26484,26487,26496,26502,26520,26551,26554,26567,26570,26574,26579,26584,26585,26592,26594,26609,26641,26697,26706,26756,26771,26773,26775,26787,26811,26850,26852,26855,26887,26888,26889,26896,26898,26899,26909,26934,26955,26966,26967,26978,26996,26999,27000,27004,27016,27026,27029,27036,27053,27074,27083,27089,27127,27142,27151,27179,27180,27184,27185,27201,27228,27229,27231,27238,27251,27263,27291,27301,27304,27311,27317,27352,27371,27379,27384,27392,27393,27395,27398,27403,27455,27458,27463,27470,27492,27507,27526,27530,27538,27556,27571,27576,27585,27605,27615,27629,27630,27642,27647,27650,27651,27658,27725,27728,27738,27743,27746,27773,27778,27780,27808,27810,27812,27842,27847,27851,27857,27867,27877,27908,27923,27928,27940,27955,27962,27973,27978,27980,27981,27985,27994,27996,28005,28008,28016,28017,28030,28036,28048,28051,28057,28058,28062,28063,28064,28065,28069,28070,28079,28094,28096,28097,28109,28121,28159,28177,28185,28199,28206,28208,28209,28220,28239,28240,28249,28263,28295,28340,28342,28343,28372,28378,28379,28385,28388,28392,28395,28399,28407,28408,28414,28417,28418,28421,28424,28431,28436,28447,28448,28462,28482,28524,28533,28540,28544,28553,28555,28557,28574,28583,28591,28592,28599,28601,28608,28636,28652,28653,28658,28660,28661,28678,28680,28683,28687,28690,28695,28761,28762,28810,28833,28842,28849,28850,28857,28858,28862,28879,28882,28884,28885,28897,28904,28920,28921,28934,28940,28956,28974,28982,28996,29005,29047,29056,29066,29069,29070,29071,29080,29102,29122,29124,29160,29161,29188,29193,29198,29233,29235,29236,29249,29251,29253,29258,29275,29276,29287,29288,29295,29297,29304,29315,29316,29321,29322,29323,29376,29392,29409,29410,29412,29421,29433,29435,29479,29482,29495,29500,29501,29511,29517,29532,29555,29556,29560,29589,29637,29655,29657,29662,29685,29688,29692,29698,29703,29719,29724,29731,29772,29789,29793,29800,29805,29814,29832,29834,29839,29857,29860,29936,29958,29961,29970,29975,29988,29999,30012,30017,30031,30038,30044,30047,30051,30058,30068,30095,30102,30130,30137,30151,30156,30163,30164,30168,30196,30201,30217,30218,30219,30223,30233,30234,30249,30260,30261,30273,30292,30295,30305,30316,30317,30325,30329,30330,30331,30333,30341,30367,30372,30377,30378,30389,30392,30395,30397,30400,30421,30424,30432,30433,30460,30461,30467,30479,30488,30559,30586,30587,30597,30671,30677,30705,30706,30707,30729,30732,30733,30747,30751,30754,30761'

update dbo.agent set IsProcessed = 0 where ID in (
	select value 
	from String_split(@list,',')
	)

  业务逻辑很简单,就是根据传入的主键ID值更新表的一个字段。表的结构无关紧要。上面SQL语句传入1000个ID值拼接成的字符串,然后调用系统的String_Split函数拆分成表。预先执行set statistics io on以便输出IO统计信息。

  

  逻辑读次数3000次,每次更新一条记录需要三个逻辑读。因为表在数据库中是使用B+树结构存储和索引的,上面的表正好是三层B+树结构,数据存储在最下面一层叶子节点,数据库每做一次聚集索引查找需要从上到下查找三个节点,需要三次逻辑读。这个结果是稳定的,不管执行多少次,list中的ID值变成多少个,结果总是3*list中的ID个数。

  查看执行计划:

  可以看到String_Split函数执行并没有逻辑读(下面的0%),拆分之后有个去重排序的过程(Distinct Sort),逻辑读占比28%。

  查看执行时间:

  

  占用62毫秒CPU时间。

  2、将ID以表变量的形式传入

declare @list varchar(max)
set @list='265828,265898,266437,266489,267215,267385,267720,267724,268170,268171,268459,268636,268752,269787,270287,271048,271213,271214,271714,272543,272544,273887,273888,274196,274378,274907,274908,275498,275948,276882,277244,277955,278519,278661,278678,279610,279683,279744,280097,280682,280705,280907,281132,281133,281835,282371,282525,283521,283564,283800,283801,284536,284634,285027,285047,285239,285598,285599,285763,285850,286874,286904,287015,287016,287174,287175,287338,287545,287971,288117,288254,288294,288350,288685,288832,289235,289239,289562,289889,290046,290112,290221,290222,290549,290574,290596,290597,290759,290913,290914,290933,291109,291454,291544,291564,291858,291862,291894,291895,292253,292285,292286,292347,292348,292352,292450,293243,293244,293368,293508,294289,294520,295149,295295,295296,295525,295616,295659,295662,295937,295938,296952,296953,297197,297228,297240,297306,298178,298219,298510,298910,299569,299889,300785,300870,301025,301556,301877,302228,303032,303113,303737,303745,303789,303943,304848,305438,305663,305987,306190,306191,306402,307007,307682,307915,308090,308091,308264,308393,309453,310134,310266,310559,310754,310972,310973,311120,313095,313119,313127,313128,313681,313751,313752,314320,315068,315069,315146,315400,315991,316194,316228,316397,316520,316546,316748,316853,317017,317263,317787,317870,317871,318091,318567,318924,318927,319591,320924,320960,321377,321458,321459,322495,322723,325511,325512,325819,325943,326492,327091,327361,327642,327818,328823,329141,329446,329760,329848,330841,330954,331232,331378,331779,332304,332371,332765,332858,333062,726726,726729,726892,727069,727304,727413,727727,728228,728377,729390,729391,729936,730069,730207,730421,730804,732352,732655,732656,732810,733753,734419,734731,734777,734863,734864,735280,736527,736805,736957,737118,737202,737203,737323,737357,737400,737416,737440,109,513,1443,1506,1510,2228,2400,2963,3785,3809,3948,4071,4791,4971,5233,6495,7249,8081,8179,8254,9230,9396,9534,10404,10885,10911,10931,11158,11333,12708,12709,14806,15031,15048,15120,15440,15953,16180,512064,512065,512822,512823,513143,513209,514394,514521,514586,514587,515129,515236,515990,516846,517240,517427,517474,517517,517717,517750,518034,518091,518100,518611,518934,518937,519091,519092,519277,519713,520499,520543,520572,520573,520862,520863,521110,521372,333063,333181,333626,333627,333683,333735,334082,334150,334421,334897,335608,335897,336967,337388,337591,337620,337686,337816,338146,338297,339348,339523,340290,340901,341015,341580,341872,341958,342278,342279,343273,343284,343527,343528,343749,344361,344362,344982,737446,737477,737499,737507,737526,737575,737611,737612,737639,737667,737777,737778,737791,737800,737808,737809,737830,737862,737869,738024,738258,738475,738568,738670,739435,739581,739683,739748,740189,740298,740451,741065,741081,741083,741357,741784,742043,742049,16373,16834,17167,17446,18637,18726,18813,19239,21630,21894,21977,22488,23236,23300,23439,23483,23614,23636,23654,23781,24315,24477,24585,24972,25234,25255,26140,26307,26780,26864,27013,27259,27286,27490,27703,28469,28475,28708,344983,344988,345201,345225,345759,345843,345844,345991,346033,346034,347246,347456,348229,348230,348974,349029,349495,349496,349808,350235,350416,351130,351719,351746,351747,351942,351943,351981,352163,352283,352816,352817,353420,353573,353795,354122,354123,354378,742222,742339,743142,743484,743546,744402,745044,745614,745700,745721,745722,745867,746597,746980,747257,747258,747938,747939,748247,748263,748425,748828,748864,749301,749536,749793,750892,751434,751867,751868,751994,752569,752629,752967,753200,753201,753783,754078,30271,30343,30908,30980,31315,31316,31593,32017,32225,32293,32669,33198,33439,33520,33577,33866,34719,34862,34866,34943,34984,35023,35037,35279,70593,71002,71551,72834,73538,74043,75335,76248,76541,77235,77378,78176,78441,79080,354706,354982,355380,356008,356372,356588,356589,357082,357117,358212,358270,358346,360092,360371,360667,360807,361936,363019,363020,363045,363415,363511,363808,363809,364051,364533,364544,364558,364559,365285,366144,367566,367913,367914,368529,369458,369485,370340,754366,754478,754770,755835,756074,756469,757191,757230,757238,758234,758249,758685,758750,758751,758814,758955,758956,759025,759235,759236,760061,760235,760236,760273,760389,760502,761061,761454,762563,763332,765492,765572,766330,766420,766421,766787,766921,767008,79538,80144,82723,82930,82932,83125,83274,83440,83556,86315,88098,88671,89093,89099,89484,89630,91200,91203,91681,91850,91862,92116,93144,93473,93933,94449,94472,94953,97505,97697,98171,98244,98606,99392,99514,99515,100404,100405,521407,521595,521958,522199,522646,522665,522773,523267,523493,523852,523855,524099,524113,524114,524250,524404,524937,524996,525026,525256,525500,526118,526134,526248,526896,527015,528252,528609,528610,528677,528826,528934,528994,529144,529373,529388,529474,529524,371195,371912,372686,373240,373241,374612,375308,375669,375670,375745,375803,375828,375898,376094,376315,376851,377005,378904,378942,379211,379486,381162,381579,382273,382415,382862,382863,382930,383243,383564,383565,383949,384086,384237,384238,384267,384273,384401,100410,101303,101553,102846,103125,103263,104054,104232,105021,105550,105551,106024,106122,106297,106314,106967,106968,106975,107334,107399,107400,107771,107772,107868,107869,108084,108085,109953,110189,110302,110303,111110,111641,111937,112071,112134,112330,113367,767196,767213,767251,767252,768769,769068,769122,769765,769826,769947,772439,772714,772757,773190,773250,773251,773411,773555,773556,773652,774277,774345,774346,774362,774539,775160,775332,775576,777984,778248,778249,778270,778389,778492,778626,778627,778790,778855,384464,386509,386625,386824,387061,387238,387239,387484,387502,387654,388086,388911,388925,388980,389104,389587,389590,390935,392004,392350,392462,392522,392724,392725,392964,393239,393347,393588,393659,393785,394614,394626,394888,395909,395910,396424,396425,396501,778898,778899,779141,779142,780077,780243,780755,781927,781928,781997,782050,782529,782604,783341,783466,783529,783698,783792,783845,784173,784255,784604,785170,785381,785476,785477,785583,785666,785824,786750,786808,787311,787562,788886,789059,789907,790310,790311,113368,113667,113743,114241,114506,114948,115273,115274,116001,117326,117963,118152,119356,120181,120182,120493,121082,121083,122587,123151,123429,123822,124010,124120,124697,124887,124892,125748,125749,125918,126126,126682,126832,127171,127616,127782,127943,128027,396582,396592,396593,396739,397221,397672,398164,398204,398280,398281,398628,398629,398733,398962,399291,399539,399591,400272,400292,400552,400960,401428,401775,401849,401850,401990,402426,402624,403250,403251,403443,403444,404183,404241,404260,404261,404354,404356,128432,128923,128955,129296,129985,130144,130145,131207,131254,131941,131942,131974'
declare @idlist idlist 
insert into @idlist  select value from String_Split(@list,',')

update dbo.agent set IsProcessed = 0 where ID in (select id from @idlist)

  其中idlist是预先定义的表变量,只有一个字段id。同样打开set statistics io on。执行结果:

  

  忽略上面字符串拆分和插入@idlist的IO次数,只关注update语句引起的IO,看到逻辑读次数是3276,比第一种方法多了276次。经过多次执行,发现逻辑读次数可能变化,有时候是有规律的变化,有时候多次执行也没有变化。最好的情况也会等于3*ID列表个数。

  查看执行计划:

  

  在这个执行计划中,去重排序(Distinct Sort)移到了主分支上,也就是查找到了1000条记录之后再进行的排序。比单独只排序ID要用更多的逻辑读次数。

  为上面update语句建立一个存储过程,然后调用存储过程,看执行结果:

Create PROCEDURE [dbo].[UpdateProcessStatus2]
(
	@IDList idlist readonly
)	
AS
BEGIN
	update dbo.agent set IsProcessed = 0 where ID in (select id from @idlist)
END
GO

  

  逻辑读变成了3071次,比直接调用sql语句减少了205次。查看执行计划也有了变化

  

   比上面少了去重排序的过程,所以逻辑读次数减少了。

  查看执行时间:

  

  执行时间比第一种方法要明显减少。

   3、总结

  string_split函数拆分会占用CPU资源,传入字符串进行拆分方法比直接传表变量方法逻辑读次数要少一点,但不太明显,总体来说,还是传入表变量略胜一筹。

posted on 2018-01-17 20:56  wangguanguo  阅读(629)  评论(0编辑  收藏  举报

导航