{"id":1092,"date":"2014-10-26T23:18:20","date_gmt":"2014-10-26T22:18:20","guid":{"rendered":"http:\/\/www.sqlserver.fr\/blog\/?p=1092"},"modified":"2020-09-01T10:06:58","modified_gmt":"2020-09-01T08:06:58","slug":"tester-si-on-a-des-enregistrements","status":"publish","type":"post","link":"https:\/\/www.sqlserver.fr\/blog\/tester-si-on-a-des-enregistrements\/","title":{"rendered":"Tester si on a des enregistrements"},"content":{"rendered":"<p>Il m&rsquo;est assez souvent arriv\u00e9 de voir des d\u00e9veloppeurs qui, pour savoir si leur programme avait des informations \u00e0 traiter, comptaient le nombre d&rsquo;enregistrement v\u00e9rifiant leurs crit\u00e8res et lan\u00e7aient leur traitement si ce nombre \u00e9tait diff\u00e9rent de z\u00e9ro. Mais en pratique, et surtout du point de vue des performances, cette fa\u00e7on de d\u00e9velopper est plut\u00f4t catastrophique.<!--more--><\/p>\n<p>Dans un premier temps, mettons en place notre jeu d&rsquo;essai :<\/p>\n<pre class=\"brush: sql; gutter: false; first-line: 1\">CREATE TABLE MaTable (Id int identity PRIMARY KEY, Valeur varchar(36));\r\nGO\r\nINSERT INTO MaTable (Valeur) SELECT CONVERT(varchar(36),NEWID())\r\nGO 1000000<\/pre>\n<p>Mettons ensuite en place\u00a0la fameuse proc\u00e9dure de comptage\u00a0:<\/p>\n<pre class=\"brush: sql; gutter: false; first-line: 1\">CREATE PROCEDURE Comptage\r\nAS\r\nBEGIN\r\ndeclare @Nb int\r\nselect @nb=count(*) from MaTable where Valeur like '1%'\r\nif @Nb&gt;0\r\n\tSELECT 'Enreg \u00e0 traiter'\r\nelse\r\n\tSELECT 'Aucun enreg'\r\nEND\r\nGO<\/pre>\n<p>Regardons un peu ce que donne l&rsquo;ex\u00e9cution de cette proc\u00e9dure en termes de charge IO et de CPU :<\/p>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-1119\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee-620x31.png\" alt=\"ChargeElevee\" width=\"620\" height=\"31\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee-620x31.png 620w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee-300x15.png 300w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee-624x31.png 624w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee-900x45.png 900w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeElevee.png 1320w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/a><\/p>\n<p>On voit dans l&rsquo;exemple une charge de 6699 lectures logiques, ce qui est plut\u00f4t beaucoup pour simplement savoir si on a ou pas un enregistrement &#8230;<\/p>\n<p>En fait, le probl\u00e8me vient du fait qu&rsquo;on s&#8217;emb\u00eate \u00e0 comptabiliser le nombre exact d&rsquo;enregistrements r\u00e9pondant \u00e0 notre p\u00e9rim\u00e8tre, \u00e0 stocker ce nombre dans une variable, et ensuite \u00e0 simplement tester si cette variable est non nulle. En enlevant une \u00e9tape (le stockage dans une variable), on permet au syst\u00e8me d&rsquo;effectuer le minimum d&rsquo;op\u00e9rations, et de s&rsquo;arr\u00eater d\u00e8s qu&rsquo;un enregistrement a \u00e9t\u00e9 trouv\u00e9.<\/p>\n<pre class=\"brush: sql; gutter: false; first-line: 1\">CREATE PROCEDURE TestComptage\r\nAS\r\nBEGIN\r\nif (select count(*) from MaTable where Valeur like '1%')&gt;0\r\n\tSELECT 'Enreg \u00e0 traiter'\r\nelse\r\n\tSELECT 'Aucun enreg'\r\nEND\r\nGO\r\nexec TestComptage<\/pre>\n<p>A l&rsquo;ex\u00e9cution, cette fois-ci, on a juste 3 lectures (dans l&rsquo;exemple), ce qui correspond \u00e0 une charge IO divis\u00e9e par 4000.<\/p>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-1120\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible-620x30.png\" alt=\"ChargeFaible\" width=\"620\" height=\"30\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible-620x30.png 620w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible-300x14.png 300w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible-624x30.png 624w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible-900x44.png 900w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2014\/10\/ChargeFaible.png 1292w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/a><\/p>\n<p>Et la charge UC est pass\u00e9e de 640ms \u00e0 une valeur inf\u00e9rieure \u00e0 la millliseconde.<\/p>\n<p>On a donc d\u00e9sormais une proc\u00e9dure efficace. En fait, le syst\u00e8me a \u00e9t\u00e9 suffisamment intelligent pour comprendre le besoin, et transformer la requ\u00eate comme si l&rsquo;on avait utilis\u00e9 la bonne syntaxe, avec le mot-cl\u00e9 EXISTS :<\/p>\n<pre class=\"brush: sql; gutter: false; first-line: 1\">CREATE PROCEDURE Existence\r\nAS\r\nBEGIN\r\nif exists(select * from MaTable where Valeur like '1%')\r\n\tSELECT 'Enreg \u00e0 traiter'\r\nelse\r\n\tSELECT 'Aucun enreg'\r\nEND\r\nGO<\/pre>\n<p>Les performances sont les m\u00eames que pour la requ\u00eate pr\u00e9c\u00e9dente, et le plan d&rsquo;ex\u00e9cution aussi est le m\u00eame.<\/p>\n<p>Le moteur est donc en mesure de rattraper quelques erreurs de d\u00e9veloppement, mais le fait de stocker le nombre d&rsquo;enregistrements dans une variable faisait\u00a0que, math\u00e9matiquement, le syst\u00e8me n&rsquo;avait pas le choix et devait faire le comptage complet pour, au final, rien.<\/p>\n<p>Il est donc tr\u00e8s important de r\u00e9fl\u00e9chir au besoin, afin de ne pas griller de la puissance inutilement.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Il m&rsquo;est assez souvent arriv\u00e9 de voir des d\u00e9veloppeurs qui, pour savoir si leur programme avait des informations \u00e0 traiter, comptaient le nombre d&rsquo;enregistrement v\u00e9rifiant leurs crit\u00e8res et lan\u00e7aient leur traitement si ce nombre \u00e9tait diff\u00e9rent de z\u00e9ro. Mais en &hellip; <a href=\"https:\/\/www.sqlserver.fr\/blog\/tester-si-on-a-des-enregistrements\/\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1092","post","type-post","status-publish","format-standard","hentry","category-article_sql"],"_links":{"self":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/1092","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/comments?post=1092"}],"version-history":[{"count":9,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/1092\/revisions"}],"predecessor-version":[{"id":1778,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/1092\/revisions\/1778"}],"wp:attachment":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/media?parent=1092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/categories?post=1092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/tags?post=1092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}