vendredi 7 février 2014

[GUSS] Election du board

Si vous êtes professionnel de SQL Server vous connaissez sans doute le GUSS dont l'objectif principal est de réunir les acteurs de la communauté en organisant un certains nombres d'événements autour de sujets techniques ou tout simplement conviviaux pour discuter de tout et de rien.

Le GUSS se modernise et pour la première fois propose une élection des membres de son board qui auront comme charge de décider de l'avenir du GUSS. Cette élection est importante car elle vous permet de choisir vos représentants pouvant soutenir et défendre vos propositions.

élection board guss

Vous trouverez la liste des différents candidats à l'adresse suivante :

http://guss.pro/candidats-au-board-du-guss-2014/

Les votes se dérouleront du 10 au 24 Février, il y aura bientôt plus d'informations sur le déroulement du scrutin. Restez attentifs aux publications sur le site du GUSS.

Ca y est vous savez tout. Maintenant il ne vous reste plus qu'à voter. On compte sur vous.

samedi 7 décembre 2013

[JSS2013] - Merci aux participants de ma session

Merci à tous les participants à la session "SSAS : Test de montée en charge avec Visual Studio. Ce fut un plaisir pour moi de présenter ce sujet orienté performance et optimisation, sujets qui sont ô combien important pour moi. J'espère avoir suscité l'envie d'utiliser la fonctionnalité load test de visual studio dans le cadre des tests de montée en charge. Pour ceux qui ne l'ont pas déjà fait, il ne vous reste plus qu'à acquérir une licence Ultimate de Visual Studio pour vous lancer dans l'aventure smiley.

WAISSO était très présent pour cet opus 2013 avec la présentation à la Keynote "10 ans de DBA" de la 2ème journée de Sham Unmar et Philippe Pimenta, la présentation sur l'agilité "le TDD avec DbFit et l'intégration continue avec TFS" présenté par Damien Maresma et la mienne. Un grand bravo à eux pour leur prestation.

Je vous laisse en téléchargement ma présentation au format PDF, dès que le webcast sera disponible je vous le mettrais à disposition.

JSS 2013

jeudi 7 novembre 2013

Venez nous rencontrer aux journées SQL Server 2013.

JSS 2013

Nous approchons à grand pas du plus gros événement autour de SQL Server en France, les Journées SQL Server. Elle se tiendront le 2 et 3 décembre au centre de conférence de Microsoft, à Issy-Les-Moulineaux.

Pour la troisième année consécutive, WAISSO sera partenaire Platinum de cet événement. Nous aurons le plaisir de présenter 2 sessions orientées productivité de développement BI.

Pour ma première participation en tant que speaker à un événement, j'ai choisi de remettre au goût du jour une bonne vieille recette, apparu en 2005, les stress tests SSAS à partir de Visual Studio. Dans cette session on parlera de design, d'optimisation, de performance et d'architecture sur SSAS bien évidemment, Multidim bien sûr et Tabular peut-être (teasing... smiley). Bien sûr nous travaillerons sur les dernières versions, SQL Server 2014 CTP 2 et Visual Studio Ultimate 2013.

Si vous avez des problématiques en lien avec ce sujet que vous auriez aimé aborder vous pouvez toujours me les soumettre. J'essaierais tant que possible de prendre en compte vos remarques.

Au plaisir de vous rencontrer le 2 et 3 décembre prochain.

JSS 2013

mardi 23 juillet 2013

[GUSS] Afterwork d'août 2013

Vous ne le saviez peut-être pas, mais le GUSS, la communauté francophone des utilisateurs de SQL Server organise des afterworks tous les 2 mois afin de permettre à tous les professionnels du produit de se réunir et d’échanger sur les nouveautés, sur des retours d’expériences, des missions ou même des opportunités.

GUSS

Le prochain se tiendra le mercredi 7 août à partir de 19H00 dans un petit bar choisi avec soin, l’Imprévu situé au 35, rue Didot 75014 Paris.

afterwork guss

Venez nous y rencontrer, le thème « Paris, SQL & Sun » servira de base à de bons échanges très techniques et enrichissant j’en suis sûr.

Pour vous y rendre : Metro 13 station Pernety (pas très loin de Montparnasse).

Pour vous y inscrire : http://guss.fr/2013/08/07/afterwork-aout-2013/

vendredi 10 mai 2013

[SSIS] Lookup paramétré en mode Full Cache

La non équi-jointure est-elle possible en mode ETL pure avec SSIS ?

Nombreux sont les cas d'utilisation où la jointure peut être un peu plus complexe qu'une égalité entre les colonnes de 2 tables. Dans le cas simple et répandu de la récupération d'un ID d'une dimension SCD2 dans le chargement d'une table de fait, il est nécessaire de recourir à une non équi-jointure. Et pourtant cette simple tâche parait complexe à faire de manière performante à l'aide de SSIS.

Rappel: La non équi-jointure consiste en l'utilisation d'opérateur de jointure différent de l'égalité comme par exemple : <, <=, >, >=, LIKE, BETWEEN ... AND ..., etc ...

Comment met-on en place le lookup paramétré dans SSIS

Prenons un exemple simple de la récupération d'un seul ID sur une dimension que l'on appellera Produit.

tables SQL Server
Prenons 2 tables simples pour illutrer le lookup paramétré
dataflow
Créons un dataflow simple avec un lookup pour récupérer l'ID d'une dimension
lookup nocache
Commençons par choisir le mode nocache pour l'exemple
lookup connection
On écrit une requête avec dans la sélection uniquement les colonnes dont on a besoin, l'ID et les colonnes impliqués dans la paramétrisation. Le but est d'avoir des metadata identique avec la requête custom
lookup columns
On map les colonnes sources qui seront les paramètres de la requête custom
lookup custom query
On utilise le ? pour signifier un paramètre
lookup parametres
Et on map les paramètres dans l'ordre d'apparition des ?

ATTENTION: Vous l'avez sans doute remarqué. Les performances de cette méthode ne sont pas satisfaisante. Mais pourquoi me direz-vous ? C'est ce que l'on va tenter d'éclaircir.

Je vous propose d'allumer notre SQL Server Profiler et lancer une trace standard pour capturer les classes d'évenement RPC:Completed, SQL:BatchStarting et SQL:BatchCompleted

sql server profiler
Voilà le résultat de la trace

L'intégralité des traces seraient trop long et indigeste. Je vais en choisir quelques extraits pour les commenter.

  • La trace commence par une phase préparatoire
    exec sp_prepare @p1 output,NULL,N'SELECT [IdProduit]
          ,[CodeProduit]
          ,[Valid_From]
    FROM [dbo].[DimProduit] dp',1
    select @p1
    go
    exec [sys].sp_describe_first_result_set N'SELECT [IdProduit]
          ,[CodeProduit]
          ,[Valid_From]
    FROM [dbo].[DimProduit] dp',NULL,1
    go
    exec sp_unprepare 3
    go
    exec [sys].sp_describe_undeclared_parameters N'SELECT [IdProduit]
          ,[CodeProduit]
          ,[Valid_From]
    FROM [dbo].[DimProduit] dp
    WHERE
     @P1 >=  dp.[Valid_From]
    and @P2 <= ISNULL(dp.[Valid_To],''9999-12-31'')
    and   dp.[CodeProduit]=@P3'
    
  • Puis elle termine par un appel de procédure par ligne
    exec sp_executesql N'SELECT [IdProduit]
          ,[CodeProduit]
          ,[Valid_From]
    FROM [dbo].[DimProduit] dp
    WHERE
     @P1 >=  dp.[Valid_From]
    and @P2 <= ISNULL(dp.[Valid_To],''9999-12-31'')
    and   dp.[CodeProduit]=@P3',N'@P1 date,@P2 date,@P3 char(10)','2013-05-02','2013-05-02','FR00000001'
    go
    

Un appel par ligne ? Un traitement séquentiel sur un moteur relationnel ? On est loin de l'état de l'art de l'ETL et même de l'état de l'art du relationnel. Vous me direz : Oui mais ... là nous avons paramétré le lookup en mode NoCache.

    Il existe effectivement 2 autres modes :
  • le mode Partial Cache
  • et le mode Full Cache

Ce que va changer le mode Partial Cache par rapport au mode NoCache, c'est qu'en début d'exécution le cache sera vide et au fur et à mesure des lectures, les lignes seront ajoutés au cache, ce qui permettra aux nouvelles lignes identiques d'être servies par le cache. Ce mode est très légerement plus performant que le mode NoCache, mais reste très peu performant et loin de la philosophie ETL.

Le mode FullCache permet de monter en cache l'intégralité des données et de traiter les jointures en mémoire de manière performante. Cependant, SSIS ne permet faire des non équi-jointure dans le cache.

A savoir: L'interface empêche de paramétrer des requêtes custom en mode FullCache aussi bien par l'interface que par les propriétés du composant ou que par les expressions du dataflow.

Propriété en PartialCache

lookup parametres

Propriété en FullCache

lookup parametres






On constate que les propriétés de paramétrisation ont disparu.

Mais alors quelle solution choisir dans le cas d'une non équi-jointure ?

En SSIS pure il reste une méthode à base de Merge Join. Mais dont l'inconvénient serait la nécessité de trier les datasets amont ce qui serait parfaitement contre-performant et vraiment non recommandable à partir du moment ou il y a plus d'une jointure de ce type à faire dans un même dataflow.

On pourrait imaginer essayer de bluffer SSIS par une expression pour lui passer dans sa propriété SqlCommand une variable contenant une requête dynamique. Mais cette feinte ne suffirait pas. Il faudrait aller plus loin à coup de requêtes paramétrés, de jointure avec une date et de boucle, pour essayer de se retrouver en situation d'équi-jointure. Une machine à gaz indigeste, contre-performante et de surcroît inmaintenable.

Force est de constater que d'utiliser SSIS en tant qu'ETL (plutôt qu'en ELT ou en séquenceur de procédures stockées) pour traiter ce genre de problématique n'est pas une solution sérieusement envisageable si l'on a beaucoup de volumétrie. Dans ce cas, il faut de manière délibérer utiliser le moteur SQL, qui est de toute façon utilisé contre nature par SSIS. Donc tant qu'à utiliser le moteur sans le savoir et de manière non maitrisé autant le faire à fond avec toute la puissance du moteur (requêtes ensemblistes, utilisation d'indexes et de statistiques) afin d'obtenir des résultats performants.

A bientôt!

jeudi 4 avril 2013

[SSAS][AMO] Construire son propre outil de gestion dynamique de cubes

Le modèle Tabular est arrivé. Mais le modèle dimensionnel n’a pas dit son dernier mot. Bon nombre d’entre vous possède encore des cubes dans ce mode. Et il faudra encore un peu de temps avant que les cubes volumineux puissent monter intégralement en mémoire.

Et justement, dans le cas où les cubes sont volumineux, il est indispensable d’avoir une stratégie de partitionnement précise afin de stabiliser les performances de calcul des cubes mais aussi d’obtenir de bonnes performances d’accès aux données.

Le partitionnement doit être ajusté aux spécificités de chaque partition et doit être aussi dynamique. Il doit maîtriser le nombre de partitions afin de ne pas saturer l’instance par un nombre de fichiers trop important qui aurait un effet contraire à celui escompté.

ATTENTION : Un trop grand nombre de partitions peut avoir des inconvénients comme le ralentissement des mises en production en alourdissant le script XMLA de déploiement, ou comme un temps de démarrage plus long du service SSAS, ou encore un ralentissement du temps de traitement des dimensions, ou bien encore un discover plus long des partitions, etc …

La modération dans la création du nombre de partition est de mise. Une stratégie réfléchie doit être appliquée.

Je vous donne un lien vers le « Analysis Services 2008 R2 Performance Guide » http://sqlcat.com/sqlcat/b/whitepapers/archive/2011/10/10/analysis-services-2008-r2-performance-guide.aspx.

Ce guide vous permettra d’affiner votre stratégie de partitionnement ( et plus encore).

    Rendre la gestion de son partitionnement dynamique est essentiel :
  • Chaque partition possède des spécificités propres (clé de partitionnement et granularité (requête source), type de stockage (MOLAP, ROLAP, HOLAP), emplacement de stockage, design d’agrégation) 
  • Chaque partition nécessite un mode de rafraichissement spécifique: Recalcule sur une période glissante, calcul de données dans le futur.
  • Les exigences de performances peuvent être variables en fonction de l’ancienneté des données. Il faut pouvoir profiter de cette exigence pour fusionner les partitions et pourquoi pas changer le type de stockage de MOLAP vers ROLAP. 
  • Créer les partitions à l’avance n’est pas une bonne chose. Il faut que l’application soit capable de créer les partitions quand il en a besoin et seulement dans ce cas.

Le traitement des dimensions doit lui aussi être dynamique. Dans un mode de croisière en fonction du type de modification on préferera le mode de processing ProcessAdd au ProcessUpdate et réciproquement. Néanmoins, il faudra que l’application soit capable de détecter le statut de processing de la dimension pour faire un ProcessFull quand ce dernier est obligatoire.

Pour toutes ces raisons, il faut rendre dynamique la gestion des processing des cubes. La meilleur approche pour le faire c’est d’utiliser l’API AMO via un language tel que Powershell, C# ou VB. Je pense que pour des raisons de maintenabilité et de cohérence d’infrastructure avec le reste de l’application ETL, il est préférable d’embarquer les scripts dans un package SSIS. De ce fait, mieux vaut préférer C# ou VB qui peuvent s’écrire dans des Scripts Tasks SSIS. Pour des raisons d’affinité avec le language C#, je construirais mes exemples autour ce celui-çi.

L’idée n’est pas de vous assister totalement mais de vous donner les clés pour construire votre outil. Il va de soi que toutes les règles de développement s’appliquent à savoir gestion des erreurs, variabilisation, création de classes, de méthodes, d’utilisation (ou pas) de listes génériques, …

Oui même en BI on soigne son code.

  1. Référence à la librairie.
  2. La première chose est de référencer notre librairie.
    using AMO = Microsoft.AnalysisServices;
    
  3. Connexion à la base :
  4. AMO.Server srv = new AMO.Server();
    srv.Connect("MonServeur");
    AMO.Database db = srv.Databases.FindByName(initialcatalog);
    
  5. Capture de la commande XMLA au serveur :
  6. Pour générer une commande à lancer au serveur il suffit de capturer un ensemble d’action entre 2 bornes marquées par la propriété CaptureXml. La valeur true signifie que la capture commence. La valeur false que la capture s’arrête.

    srv.CaptureXml = true;
    … (Voir dans le 3)
    srv.CaptureXml = false;
    
    
  7. Les différentes commandes :
  8. Voici quelques commandes possibles pour gérer vos cubes.

    1. suppression des partitions:
    2. Soit il est possible de supprimer l’intégralité des partitions de tous les cubes comme suit :
      foreach (AMO.Cube Cube in db.Cubes){
           foreach (AMO.MeasureGroup Meg in Cube.MeasureGroups){
                foreach (AMO.Partition part in Cube.Partitions){
                        part.Drop();     
                }
           }
      }
      
      

      Soit il est possible de supprimer une partition en fonction d’une liste :

      AMO.Cube cube = db.Cubes.FindByName("BaseASNomCube");
      AMO.MeasureGroup Meg = cube.MeasureGroups.FindByName("BaseASNomGroupeMesure");
      AMO.Partition part = Meg.Partitions.FindByName("BaseASNomPartition");
      part.Drop();
      
    3. La création des partitions :
    4. AMO.Partition part = Meg.Partitions.FindByName("NomPartition");
      if (part == null)
      {
      part = Meg.Partitions.Add("NomPartition");
      switch ("MonModeStockage")
      {
      case "molap":
      part.StorageMode = AMO.StorageMode.Molap;
      break;
      case "holap":
      part.StorageMode = AMO.StorageMode.Holap;
      break;
      case "rolap":
      part.StorageMode = AMO.StorageMode.Rolap;
      break;
      default:
      part.StorageMode = AMO.StorageMode.Molap;
      break;
      }
      
      datasource = db.DataSources.FindByName("MonDataSourceName");
      part.Source = new AMO.QueryBinding(datasource.ID, "MaRequête"]);
      
      // affectation du premier design d'aggregation trouve
                         
      if (Meg.AggregationDesigns.Count > 0)
      {
      part.AggregationDesignID = Meg.AggregationDesigns[0].ID;
      }
      }
      
      part.Update(AMO.UpdateOptions.ExpandFull);
      
    5. Le processing des dimensions :
    6. AMO.Dimension dim = db.Dimensions.FindByName("NomDimension");
      
      if (dim == null)
      {
      
      // Si les partitions ne sont pas processer alors on les process FULL sinon on applique le paramétrage.
      if (dim.State.ToString() == "Processed")
      {
      switch (row["ProcessingType"].ToString())
      {
      case "U":
      dim.Process(AMO.ProcessType.ProcessUpdate);
      break;
      case "F":
      dim.Process(AMO.ProcessType.ProcessFull);
      break;
      case "A":
      dim.Process(AMO.ProcessType.ProcessAdd);
      break;
      default:
      dim.Process(AMO.ProcessType.ProcessDefault);
      break;
      }
      }
      else
      dim.Process(AMO.ProcessType.ProcessFull);
      
      
    7. Le processing des partitions :
    8. AMO.Partition part = Meg.Partitions.FindByName(p.NomPartition);
      part.Process(AMO.ProcessType.ProcessFull);
      
      

      Il est possible de faire une ProcessData + un ProcessIndex, qui reviendrait au même que le process Full et serait même plus performant.

    9. Le processing des groupes de mesures liés :
    10. Le processing des groupes de mesure liés n’est pas automatique. Traiter le groupe de mesures auquel il est lié ne suffit pas.

      // parcours des cubes à la recherche des groupes de mesures liés
      foreach (AMO.Cube cube2 in db.Cubes)
      {
      foreach (AMO.MeasureGroup Meg2 in cube2.MeasureGroups)
      {
      if (Meg2.IsLinked)
      Meg2.Process(AMO.ProcessType.ProcessDefault);
      }
      }
      
      
  9. Lancement des commandes :
  10. Les commande d’exécute grâce à la méthode ExecuteCaptureLog qui prends 2 arguments booléen : Transaction et Parallel afin de jouer sur la parallélisation et sur la gestion des transactions (par lot ou à la fin).

    Exemple de code pour l’exécution. Attention j’ai utilisé une méthode et une variable non définit dans cet article.

    AMO.XmlaResultCollection results = srv.ExecuteCaptureLog(, parallel);
    
    foreach (AMO.XmlaResult result in results)
    {
    foreach (AMO.XmlaMessage message in result.Messages)
    {
    if (message.GetType().Name == "XmlaError")
    {
    statutexecution = false;
    ScriptResult(srv, statutexecution,message.Description);
    }
    else
    {
    statutexecution = true;
    ScriptResult(srv, statutexecution, message.Description);
    }
    }
    }
    
    
  11. Récupération du contenu d’une variable de type object dans un script task :
  12. Il peut s’avérer utile dans ce type de tâche de ramener des informations de listes dans un script et de les récupérer.

    Pour se faire :

    DataTable dt = new DataTable();
    OleDbDataAdapter adapter = new OleDbDataAdapter();
    adapter.Fill(dt, Dts.Variables["ListePartitionASupprimer"].Value);
    
    //Puis on fini par un dispose
    adapter.Dispose();
    dt.Dispose();
    
    

    Ensuite vous pouvez récupérer les valeurs des colonnes pour chaque ligne comme suit :

    foreach (DataRow row in dt.Rows)
    {
          row["BaseASNomCube"].ToString())
    //etc …
    }
    
    
  13. Ajout de journalisation dans votre package :
  14. Si vous souhaitez récupérer des informations de jounalisation dans votre table de log (sys.ssislog). Voilà ce que vous pouvez ajouter dans votre code :

    Dts.Log("Création de la partition machin", 0, null);
    Dts.Events.FireWarning(0,Dts.Variables["System::TaskName"].Value.ToString(),"Mon message", "", 0);
    

    Si vous souhaitez faire échouer votre package vous pouvez utiliser cette commande :

    Dts.Events.FireError(0, Dts.Variables["System::TaskName"].Value.ToString(), description, "", 0);
    
  15. Ecriture de la commande XMLA dans un fichier :
  16. Il peut être intéressant de générer le fichier XMLA lancé au serveur dans une optique de Debug.

    Voici un code qui pourrait vous être utile.

    StringCollection CapturedXmla = new StringCollection();
    CapturedXmla = srv.CaptureLog;
    if (CapturedXmla.Count > 1){
    StreamWriter sw = new StreamWriter(FileName);
    sw.AutoFlush = true;
    sw.Write(srv.ConcatenateCaptureLog(true, true));
    sw.Close();
    }
    
    

J’espère que tous ces petits bout de code pourront vous permettre d’aller au bout de vos projets ou bien que cet article vous aura permis de réfléchir autour de votre stratégie d’exploitation de vos cubes SSAS.

jeudi 21 février 2013

[SSIS] Legacy mode vs modèle de déploiement de projet.

Vous ne le savez peut-être pas, mais la dernière version de SSIS a connu de nombreuses modifications. L’une d’entre elle est l’unité de déploiement. Cette modification va chambouler nos habitudes de développeurs en amenant la notion de modèle de déploiement projet.

Pour les nouveaux projets démarrant sur 2012, le choix du type de projet se pose dès la phase de conception (voir même avant). Et pour ceux qui aimeraient migrer leur projets SSIS en 2012, la question de migration dans le nouveau mode se pose, bien qu’elle n’ait rien d’obligatoire.

Ce mode de déploiement est le mode par défaut. Cependant, à tout moment, il est possible de convertir son projet SSIS de mode projet vers mode package et réciproquement. Bien que la conversion ne sera sans doute pas sans douleur en fonction des spécifités d’organisation et devariabilisation inhérente à votre projet.

Le projet SSIS à la mode 2005 qui aura tenu 3 versions a été relégué au rang de mode Legacy. Il n’est cependant pas supprimé (bonne nouvelle). Les 2 types de projets existent et peuvent coexister. Cependant avec un nom comme Legacy, sa pérennité n’est vraisemblablement pas assurée.

Voici un petit listing des + et des – du nouveau mode. Cela n’engage que moi. N’hésitez pas partager votre retour d’expérience sur vos implémentations du nouveau mode en commentant mon article.


    Avantages du nouveau mode :
  1. Le logging est natif et un jeu de rapports standards est fourni.
  2. Les déploiements sont versionnés il est possible de revenir à une version précédente sans effort en cas d’anomalie.
  3. La paramétrisation des propriétés offre plus de stabilité que la version précédente, dans laquelle les propriétés étaient identifiées par leur nom.
    Points faibles et manquement :
  1. L’impossibilité de partager des paramètres au-delà du projet empêche de découper le projet ETL en unité plus fine. Avec une paramétrisation projet, il faut définir et maintenir tous les paramètres partagés entre tous les différents projets de l’instance.
  2. Le travail en équipe est rendu moins facile. Il devient difficile de faire travailler des développeurs sur des sujets séparés au sein de la même solution. Ou sinon de bien faire attention à ne jamais récupérer du gestionnaire de code source (Source Safe, TFS, etc …) une autre version de package que la dernière valide afin de pouvoir builder son projet et ne pas causer de régression. Et si jamais un développeur doit faire des modifications au niveau du projet (paramètre, ajout d’un package, etc ….), cela peut s’avérer compliqué.
  3. L’impossibilité d’appeler un même package avec plusieurs environnements d’exécution. On peut comprendre qu’il ne soit possible de n’exécuter qu’un seul environnement par exécution du fait de son nom. Mais dans les versions précédente il était possible d’affecter plusieurs configurations pour traiter le spécifique et réutiliser des configurations communes. Ceci aurait pu donner plus de flexibilité pour le développeur.
  4. L’impossibilité de classer les environnements dans des répertoires. Dans des projets de grande ampleur, cela peut devenir vite indigeste.

Le nouveau mode offre de nouvelles possibilités, mais impose aussi beaucoup de contraintes. A mon sens, il a plutôt vocation à faciliter les échanges entre une équipe de développement et l’exploitant (ou la personne qui réceptionne le livrable). Néanmoins, dans des projets d’envergures, pour des projets d’alimentation sur des domaines fonctionnelles indépendant mais mutualisable, ou pour la maintenance évolutive, ce mode dans son état actuelle est moins adapté que le mode Legacy.

Pour les nouveaux projets la question est légitime : partir en mode projet ou legacy. Pour les projets de migration vers 2012, pour ceux qui ont investi beaucoup de temps et d’argent dans une structuration de leur projet, je leur conseillerais de migrer leur solution ISO sans passer au mode projet. Rien ne presse. Microsoft dévoilera bien assez tôt ses intentions sur le mode Legacy. Et là ce sera le moment d’agir.