Manipulation de bits

L'un des principaux avantages de posséder un langage riche est de pouvoir traiter certaines données à un niveau beaucoup plus bas que par des commandes classiques...

Les fonctions de manipulations de bits dans SQL Server en sont un bon exemple.

Pour rappel, on trouvera notamment :

  • le AND logique : &
  • le OR logique : |

Le gros avantage de ces fonctions bas niveau est un accroissement considérable des performances lors de traitements longs par exemple (insertion dans plusieurs tables en une seule procédure stockée).

Nous allons voir un exemple concret de manipulation de ces bits permettant d'exploser nos perfs (véridique sur un test à échelle réelle).

J'ai un formulaire de type "Dites-nous tout sur vous" dont je souhaite stocker en base les réponses des utilisateurs. Nous allons nous focaliser sur une question de ce questionnaire pour ne pas allonger ce post mais le principe restera le même pour l'ensemble du formulaire.

La question-exemple (à choix multiple) sera "comment occupez-vous vos loisirs ?". Les réponses seront les suivantes :

Sport, Culture-Découverte, Détente, Musique-Concerts, Auto-Moto, Cine-TV, Santé-Beauté-Forme, Bricolage, JeuxVideos, Voyages

Notre table d'utilisateur existe déjà :

T_Personne(PersonneId,Nom,Prenom,...)

Un cas classique voudrait que l'on conçoit nos tables de réponses de la façon suivante :

schéma1

On peut éventuellement se passer de la table T_Reponse dans notre cas puisque ses valeurs seront uniquement {Oui, Non, NULL}.

On voit néanmoins que pour chaque réponse de l'utilisateur, on insère une ligne dans la table d'association T_Reponse_Question. Idem pour la mise à jour voire la suppression...

La première étape de l'amélioration de nos perfs consiste à dénormaliser notre schéma, pour obtenir la table de réponses aux questions suivante (on conserve uniquement la table T_Personne et celle-ci) :

table_denormalized

Le champ PersonneId sera à la fois clé primaire et clé étrangère par rapport à la table T_Personne.

Côté code .NET, une enum "flags" dont la définition suit permettra de récupérer toutes les réponses :

[Flags] 
public enum Loisirs
{
Sport = 1
,CultureDecouverte = 2
,Detente = 4
,MusiqueConcert = 8
,AutoMoto = 16
,CineTV = 32
,SanteBeauteForme = 64
,Bricolage = 128
,JeuxVideo = 256
,Voyages = 512
}

Dans la page, si des CheckBox permettent à l'utilisateur de répondre, chaque réponse est récupérée comme suit :

monUser.Loisirs = ((chkReponse0.Checked ? Loisirs.Sport : 0) 
|(chkReponse1.Checked ? Loisirs.CultureDecouverte : 0)
| (chkReponse2.Checked ? Loisirs.Detente : 0)
| (chkReponse3.Checked ? Loisirs.MusiqueConcert : 0)
| (chkReponse4.Checked ? Loisirs.AutoMoto : 0)
| (chkReponse5.Checked ? Loisirs.CineTV : 0)
| (chkReponse6.Checked ? Loisirs.SanteBeauteForme : 0)
| (chkReponse7.Checked ? Loisirs.Bricolage : 0)
| (chkReponse8.Checked ? Loisirs.JeuxVideo : 0)
| (chkReponse9.Checked ? Loisirs.Voyages : 0));

Ainsi, côté SQL, pour une insertion ou une mise à jour, notre procédure stockée aura comme paramètre une variable @Loisirs de type INT, utilisée comme suit :

INSERT INTO [T_Question_Reponse_Denormalized] 
([PersonneId]
,[Sport]
,[Culture-Decouverte]
,[Detente]
,[Musique-Concert]
,[Auto-Moto]
,[Cine-TV]
,[Sante-Beaute-Forme]
,[Bricolage]
,[JeuxVideo]
,[Voyages])
VALUES
(1
,@Loisirs & 1
,@Loisirs & 2
,@Loisirs & 4
,@Loisirs & 8
,@Loisirs & 16
,@Loisirs & 32
,@Loisirs & 64
,@Loisirs & 128
,@Loisirs & 256
,@Loisirs & 512)


Pour récupérer nos réponse, notre SELECT ressemblera à ceci :

SELECT [PersonneId] 
,([Sport] * 1
|[Culture-Decouverte] * 2
|[Detente] * 4
|[Musique-Concert] * 8
|[Auto-Moto] * 16
|[Cine-TV] * 32
|[Sante-Beaute-Forme] * 64
|[Bricolage] * 128
|[JeuxVideo] * 256
|[Voyages] * 512) AS Loisirs
FROM [COACH].[dbo].[T_Question_Reponse_Denormalized]
WHERE PersonneId = 1

Enfin, côté code .NET, un simple :

(Loisirs)(int)reader["Loisirs"]; 

permettra de récupérer l'ensemble des réponses pour la question.

On remarquera donc comme principaux avantages :

  • manipulation de bits donc accroissement des performances générales
  • une seule ligne impactée pour l'insertion / la mise a jour / la suppression

L'inconvénient majeur à mon avis est l'extension du nombre de questions / réponses qui impose la création d'une nouvelle table par question et d'une nouvelle colonne par réponse....

Si les performances restent la contrainte numéro 1 (ce qui est le cas sur des applications Web), cette solution est à envisager...

Publié lundi 14 avril 2008 17:16 par guldan
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

# re: Manipulation de bits @ mardi 15 avril 2008 09:43

Bon post, c'est bien expliqué (manquerait pê un peu de détails sur la récupération des Loisirs côté .NET, pour l'affichage par exemple)

Mais euh... pourquoi faire un champ par "loisir" (et donc avoir x bits) au lieu de n'avoir qu'un seul champ 'loisirs', type int/bigint dans lequel serait stocké la valeur totale (la même que renvoyée par ton dernier select) ?

Ca ne limite pas le nombre de loisirs, ça fait moins de calculs pour l'insertion et la récupération. Par contre, c'est un peu plus chiant s'il faut faire une recherche sur "qui fait tel loisir" (encore que...).

Qu'en penses-tu ?

(et puis j'aime pas ta façon d'indenter, avec la virgule en début de ligne :p)

jupolj

# re: Manipulation de bits @ mardi 15 avril 2008 10:19

ta remarque est pertinente. Dans mon cas précis, plusieurs services vont aller taper les résultats pour stats et autres analyses (BI,marketing, etc) et ils ont besoin d'un minimum de clarté sur le modèle de données...

Dans l'absolu, ton idée est à mon avis l'extension idéale d'un traitement binaire côté BD pour des questionnaires, d'autant plus qu'une indexation sur le champ des réponses est alors envisageable.

guldan


Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01