{"id":837,"date":"2013-04-12T00:00:36","date_gmt":"2013-04-11T22:00:36","guid":{"rendered":"http:\/\/www.sqlserver.fr\/blog\/?p=837"},"modified":"2026-05-02T14:30:58","modified_gmt":"2026-05-02T12:30:58","slug":"purge-massive-de-donnees","status":"publish","type":"post","link":"https:\/\/www.sqlserver.fr\/blog\/purge-massive-de-donnees\/","title":{"rendered":"Purge massive de donn\u00e9es"},"content":{"rendered":"<p>Dans l&rsquo;article <a title=\"D\u00e9coupage de gros traitements\" href=\"https:\/\/www.sqlserver.fr\/blog\/decoupage-de-gros-traitements\/\">D\u00e9coupage de gros traitements<\/a>, j&rsquo;\u00e9voquais le fait de traiter par paquets une insertion massive de donn\u00e9es.<\/p>\n<p>Mais sans aller chercher si compliqu\u00e9, il est, de mani\u00e8re beaucoup plus courante, tr\u00e8s utile de d\u00e9couper par lots des traitements tels que la purge de donn\u00e9es.<!--more--><\/p>\n<p>Prenons par exemple une table contenant un million d&rsquo;enregistrements, concernant les donn\u00e9es depuis un certain nombre d&rsquo;ann\u00e9es.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">create table MesDonneesHistoriques (Id bigint identity PRIMARY KEY,\r\n\t\t\t\t\t\t\t\t\tDateEvenement datetime,\r\n\t\t\t\t\t\t\t\t\ttimestamp,\r\n\t\t\t\t\t\t\t\t\tGUID uniqueidentifier DEFAULT NEWID(),\r\n\t\t\t\t\t\t\t\t\tChaine varchar(MAX) DEFAULT REPLICATE('TEST',100),\r\n\t\t\t\t\t\t\t\t\tLongueur AS LEN(Chaine) PERSISTED)<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2013\/04\/Taille_Initiale.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-853\" alt=\"Taille_Initiale\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2013\/04\/Taille_Initiale.png\" width=\"465\" height=\"48\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2013\/04\/Taille_Initiale.png 465w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2013\/04\/Taille_Initiale-300x30.png 300w\" sizes=\"auto, (max-width: 465px) 100vw, 465px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2013\/04\/RepartitionInitiale.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-854\" alt=\"RepartitionInitiale\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2013\/04\/RepartitionInitiale.png\" width=\"140\" height=\"314\" \/><\/a><\/p>\n<p>Supposons ici que nous cherchons \u00e0 faire du m\u00e9nage, et \u00e0 supprimer par exemple toutes les donn\u00e9es ant\u00e9rieures \u00e0 l&rsquo;ann\u00e9e 2005.<\/p>\n<p>Une premi\u00e8re approche consisterait \u00e0 \u00e9crire une simple requ\u00eate d&rsquo;effacement :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">delete from MesDonneesHistoriques where DateEvenement&lt;'20050101'<\/pre>\n<p>Syntaxe simple, mais pas forc\u00e9ment tr\u00e8s efficace, puisque la dur\u00e9e d&rsquo;ex\u00e9cution est constat\u00e9e \u00e0 pr\u00e8s de 4 minutes sur la machine sur lequel le test a \u00e9t\u00e9 r\u00e9alis\u00e9 et qu&rsquo;il s&rsquo;agit surtout de 4 minutes pendants lesquelles la table est compl\u00e8tement bloqu\u00e9e.<\/p>\n<p>SQL Server Execution Times:\u00a0 \u00a0CPU time = 17720 ms, \u00a0elapsed time = 230140 ms.<\/p>\n<p>Un tout petit peu plus compliqu\u00e9, mais nettement plus efficace, surtout dans le cas de bases de donn\u00e9es en mode de r\u00e9cup\u00e9ration simple, le traitement par lot permet de faire le m\u00eame travail.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">set nocount on\r\ndeclare @Depart int\r\nselect @Depart=1 -- Pour fixer un @@ROWCOUNT&gt;0\r\nWHILE @@ROWCOUNT&gt;0\r\n\tdelete TOP (1000) from MesDonneesHistoriques where DateEvenement&lt;'20050101'<\/pre>\n<p>Cette fois-ci, la dur\u00e9e d&rsquo;ex\u00e9cution totale constat\u00e9e est d&rsquo;environ 8 minutes.<\/p>\n<p>C&rsquo;est effectivement plus long, mais ce qu&rsquo;il faut surtout retenir, c&rsquo;est qu&rsquo;entre chaque lot, les \u00e9ventuels autres traitements tournant en parall\u00e8le peuvent passer, et il y a donc un impact bien moindre sur les autres processus applicatifs. Dans notre cas (377000 lignes effac\u00e9es environ), la suppression s&rsquo;est faite en 377 lots ce qui en faisant la division, nous donne une s\u00e9rie de petit blocages d&rsquo;environ 1.25 seconde.<\/p>\n<p>Les valeurs de performances cit\u00e9es ci-dessus ont \u00e9t\u00e9 relev\u00e9es sur une machine virtuelle plut\u00f4t sous-dimensionn\u00e9e, mais la r\u00e8gle est tout de m\u00eame \u00e0 retenir et surtout \u00e0 appliquer sur des serveurs de production : lorsque l&rsquo;on souhaite faire une purge massive, il est nettement pr\u00e9f\u00e9rable d&rsquo;y aller petit bout par petit bout, plut\u00f4t que comme une brute &#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dans l&rsquo;article D\u00e9coupage de gros traitements, j&rsquo;\u00e9voquais le fait de traiter par paquets une insertion massive de donn\u00e9es. Mais sans aller chercher si compliqu\u00e9, il est, de mani\u00e8re beaucoup plus courante, tr\u00e8s utile de d\u00e9couper par lots des traitements tels &hellip; <a href=\"https:\/\/www.sqlserver.fr\/blog\/purge-massive-de-donnees\/\">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-837","post","type-post","status-publish","format-standard","hentry","category-article_sql"],"_links":{"self":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/837","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=837"}],"version-history":[{"count":10,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/837\/revisions"}],"predecessor-version":[{"id":1934,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/837\/revisions\/1934"}],"wp:attachment":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/media?parent=837"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/categories?post=837"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/tags?post=837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}