Connexion



Register
Forgot Password ?

Inscription

L'inscription à DotNetNuke France est entièrement gratuite et vous permet de profiter pleinement des outils mis à votre disposition. L'inscription ne donne néanmoins pas le statut d'adhérent à l'association.

  • Discutez sur le forum et suivez son activité
  • Répondez aux articles
  • Soutenez l'association
  • Téléchargez les traductions

 

DotNetNuke France

Association francophone

Maintenir un site Dnn performant au fil du temps

Auteur : Sébastien Fichot

Date de pulication : 20 October 2010

Classement : Actualité, Développement

Article consulté 2170 fois Article Rating (5 votes)
 

Le symptôme le plus significatif d'un site DotNetNuke mis en place depuis plusieurs années et non maintenu est la lenteur : lenteur sur le recherche, lenteur au premier chargement, lenteur à heures fixes sans trop savoir pourquoi, etc. C'est assez rageant quand on voit la rapidité avec laquelle s’exécute une instance DotNetNuke au début de sa vie, et incompréhensible du côté de la DSI qui a employé des méthodes radicales et coûteuses (nouveau serveur Web).

Pour rendre un site un peu vieillissant plus rapide, il existe cependant des méthodes un peu plus compréhensives du budget qui s'appuient sur des constatations simples. Nous les aborderons dans cet article comme une liste de choses à faire pour que votre site continue de bien fonctionner au fil du temps. Bien entendu, un nouveau serveur Web aide aussi ;)


    Mettre à jour DotNetNuke


    DotNetNuke s'améliore constamment, et son architecture logicielle s'affine un peu plus chaque jour. Pour profiter des améliorations, il faut appliquer régulièrement les mises à jour. Pour découvrir comment réaliser une mise à jour, vous pouvez lire l'article Mettre à jour DotNetNuke. Vous pouvez aussi préférer certaines solutions automatiques comme Papayas DNNAutoUpgrade

    Sur la page d'accueil du site, vous pouvez aussi prendre connaissance en temps réel de la publication d'une nouvelle version. Il vous suffit de regarder l'encart de droite qui affiche la dernière version, synchronisé depuis un service CodePlex sur la publication des releases par la Core Team.


    Conserver le site en mémoire


    Chaque fois qu'un appel est fait sur votre site, DotNetNuke interroge le cache IIS afin de savoir si il doit générer le contenu ou utiliser celui déjà généré et stocké en mémoire. Ce processus évite la re-génération du contenu similaire à un grand nombre de visiteurs.
    Ce cache est cependant vidé à chaque fois que IIS recycle sa mémoire (Paramètres du pool applicatif).
    DotNetNuke ajoute sur à cela un cache basé sur un autre modèle, permettant d'avoir à générer deux fois le même contenu encore moins souvent.

    Le recyclage de la mémoire est bon pour le serveur Web, il libère de la ressource pour les autres services, et si il a swappé une partie de sa mémoire, il libère du disque et permet la défragmentation de zones autrement constamment occupées.

    Seulement, le premier utilisateur visitant le site après le recyclage subit un chargement dû au redémarrage de l'application, parfois long de plusieurs secondes (Certains rapportent de 11 à 25 secondes). Pour éviter le désagrément sans perdre les avantages du recyclage mémoire, Anton Bursev a développé un petit service IIS qui va réveiller l'application après son recyclage (Keep It Warm). Le procédé est assez similaire au PaceMaker réalisé par Jean-Sylvain Boige pour Dnn 4. La mémoire est recyclée, et le premier utilisateur ne subi pas de chargement.

    Pour utiliser la solution, suivez simplement le How-to présenté sur la page CodePlex du service. Le Service est spécialement conçu pour l'hébergement DotNetNuke, puisqu'il ne va pas simplement réveiller l'hôte du portail, mais aussi chacun des portails pères ou enfants installés sur l'hôte, et les mettre en mémoire : Keep Alive Service For IIS 6.0/7.5. Notons également que le service réveillera tous les autres types de site web présents sur le serveur Web, quelque soit la technologie utilisée (ASP.NET, PHP, CGI, ...).

    Réduire le nombre de tâches planifiées exécutées le jour (au profit de la nuit)


    Une tâche planifiée est une routine pouvant s’exécuter à intervalle fixe sur programmation d'un hôte (Pour voir comment en fabriquer vous-même, cliquez ici) . Les tâches sont insérées les unes après les autres dans un thread séparé du thread de l'hôte DotNetNuke principal (Aka. : Celui qui sert les visiteurs), et s'y exécutent tant que la tâche n'est pas terminée. Cela permet au thread principal de rester disponible pour les visiteurs, et servir les pages même si une indexation ou une autre tâche lourde s’exécutent en fond.

    Seulement parfois une tâche planifiée a un objectif si vaste, que son impact sur le serveur SQL est mesurable par les visiteurs. D'autre fois, pour des besoins de sauvegarde, il faut pouvoir déterminer avec une certaine exactitude le laps de temps dans lequel la tâche planifiée s’exécute.

    Voici les rudiments qui vous permettront d’exécuter la nuit ce que le jour ne saurait tolérer.

    Tout d'abord, configurez le planificateur de tâches pour que son exécution soit en mode "Automatique" depuis la page Hôte > Paramètres de l'hôte > Paramètres avancés > Autres paramètres, et enregistrez la configuration. Le mode automatique, ou mode "Timer", permet de définir des tâches exécutées à des heures où aucun visiteur ne visite le site (la nuit). Il existe deux autres modes : Le mode "Utilisateur" ou "Méthode de requête", qui exécute ses actions lorsqu'un visiteur visite le site, et le mode "Désactivé", qui aboli le système.



    Rendez-vous ensuite sur le centre de gestion des tâches planifiées : Hôte > Planificateur.








    A partir de cet écran, configurez toutes les tâches planifiées de votre choix afin qu'elles s’exécutent "chaque 1 jour".
    Prenons l’exemple de la tâche planifiée nommée "Purge Users Online". Indépendamment de la fonction de cette tâche planifiée (Effacer le cache mémoire comptant les utilisateurs en ligne), voyons quelle micro-configuration adopter pour cette tâche : 



    • Nom : Le nom de la tâche planifiée. Peut être changé comme bon vous semble.
    • Planifiée : Indique si la tâche planifiée est active. Vous pouvez activer / désactiver une tâche sans avoir besoin de l'ajouter / supprimer à chaque fois.
    • Récurrence : Cette valeur nous intéresse particulièrement, puisqu'elle permet de définir le laps de temps entre les exécutions. Exemple: "5" et "Minutes" pour lancer la tâche toutes les 5 minutes. Laissez vide pour désactiver la temporisation, et dans notre cas, définissez sur 1 jour.
    • Nouvelle tentative : Cette valeur permet de définir le laps de temps à laisser écouler si l’exécution mène à une erreur. Exemple : "5" et "Minutes" pour tenter de relancer la tâche toutes les 5 minutes. Cette valeur dépend évidemment de ce que fait la tâche planifiée. Laissez la valeur par défaut si vous avez un doute.
    • Démarrage sur : Cette valeur permet de définir l’évènement sur lequel la tâche lancera son éxécution. Exemple : sélectionnez "APPLICATION_START" pour démarrer cet évènement au moment du lancement de l'application web. Dans notre cas, laissez le choix sur "Aucune".
    • Catch Up actif : Si cette option est cochée, en cas d'indisponibilité du serveur, l'évènement sera lancé une seule fois pour toutes les planifications n'ayant pas été lancées durant la période d'indisponibilité. Cela dépend encore de la fonction finale de la tâche planifiée, mais pour avoir une vraie exécution à heure fixe, je vous recommande d'activer le ketchup.
    Les autres éléments de configuration ne nous importent pas ou peu pour la programmation des tâches.

    Au final, vous devriez obtenir une liste similaire à celle-ci : 



    Vous pourriez vouloir changer la fréquence d’exécution des "petites" tâches, comme "Purge Users Online", qui remet à zéro le nombre d'utilisateurs connectés, ou encore "Send Log Notifications" qui, si vous avez spécifié un email dans Site > Observateur d’évènement, vous permet d'envoyer les erreurs du site par courriel. Libre à vous d'en décider ainsi.

    Et maintenant, le rôle de l'administrateur du site web devient rigolo : A l'heure de la nuit où vous souhaitez que les tâches s’exécutent, levez vous de votre lit, connectez vous, rendez-vous sur Hôte > Planificateur, éditez chacune des tâches planifiées et cliquez sur "Exécuter maintenant". La première exécution fixera automatiquement l'heure d’exécution des tâches suivantes. Vous pourriez aussi vouloir les exécuter dans un ordre spécifique ... Personnellement, j'ai utilisé une Macro avec un plugin Firefox qui a exécuté tout cela pour moi. Ça peut aussi être un WebTest depuis Visual Studio, à vous de voir. 

    Le lendemain, en accédant à l'historique de la première et de la dernière tâche planifiée lancée la veille, vous devriez pouvoir déterminer le temps d’exécution des tâches planifiées, et donc, ajuster votre Backup automatique, par exemple.

    Réduire la taille des images


    Saviez-vous que les images que vous chargez peuvent être optimisées pour leur diffusion sur Internet ? Une image JPEG affichée en page d'accueil peut rallonger de plusieurs secondes l'affichage de votre site !  Il existe encore une fois beaucoup de solutions proposant ce service. Je vous propose de découvrir Smush It qui, à l'aide d'un plugin Firefox, va rendre plus simple une bonne partie des traitements.

    Installez l'extension depuis Firefox en recherchant YSlow dans le menu Extensions. (Outils > Modules complémentaires > Catalogue)
    (Ne cherchez pas l'extension pour Chrome, elle n'existe pas. Utilisez plutôt le service directement depuis le site web : http://www.smushit.com).

    Le service est maintenant encapsulé dans les outils développeurs de Yahoo!, YSlow.
    Redémarrez Firefox, puis affichez votre site. En bas à droite de l'écran, cliquez sur le boutton YSlow.




    Puis cliquez sur l'onglet "Tools", puis "All Smush It".




    Après avoir cliqué, un second onglet s'ouvre, et vous pouvez voir le nombre de kilos gagnés sur l'optimisation des images avec une meilleure compression. 

    Cliquez sur "Download Smushed Images".Vous récupérez un fichier ZIP, que vous décompressez quelque part. Après avoir optimisé toutes les pages (images) de votre site, remplacez les dans leur dossier d'origine sur le serveur Web. Le gain est considérable : plusieurs méga-octets d'économisés sur certains sites, sans perdre en qualité d'image.





    Placer les images sur un autre nom de domaine (et modifier RadEditor pour qu'il incorpore la solution)


    La plupart des navigateurs autorisent 6 connexions simultanées sur un nom de domaine pour télécharger les ressources en parallèle. Certains ne vont autoriser que 2 connexions simultanées. Si vous placez les images sur un autre nom de domaine, votre site s'affiche plus rapidement. Pour ce faire, vous pouvez créer un sous-domaine de votre nom de domaine (Ex. : images.nomdedomaine.com) et le faire pointer vers votre serveur, puis demander à IIS de rediriger les requêtes vers un dossier spécifique, le root de votre site web.

    Modifiez aussi RadEditor pour qu'il accepte de changer le nom de domaine à l'insertion d'une image en suivant la procédure ci-dessous :
    Recherchez sur votre server Web le fichier "ImageManager.ascx". Editez le avec Visual Studio par exemple.
    A la ligne 233, remplacez 
    newImage.src = this._currentItem.get_url();
    par
    newImage.src = "http://images.monsite.com/" + this._currentItem.get_url();
    où "images" constitue le sous domaine sur lequel se trouve les images.

     Par exemple, si votre domaine est www.monsite.com, et vos images sur mesimages.monsite.com, vous aurez : 
    newImage.src = "http://mesimages.monsite.com/" + this._currentItem.get_url();
    Si votre domaine est www.monsite.com, et vos images sur mesimages.MonAutreNomDeDomaine.com, vous aurez : 
    newImage.src = "http://mesimages.MonAutreNomDeDomaine.com/" + this._currentItem.get_url();

     L'important reste que votre nom de domaine pointe bien vers le bon site.

     Enregistrez le fichier, et testez l'insertion d'une image. L'URL insérée devrait utiliser le nom de domaine spécifié.




      Note : Si vous utilisez SSL, il vous faudra un nouveau certificat SSL Single-host ou un certificat Wildcard sur le sous domaine.

    Identifier les tables lourdes


    "La taille des données contenue dans la base de donnée affecte directement sa capacité à traiter rapidement l'appel à ces données." 
    De fait, il semble important d'identifier rapidement quelles données sont stockées dans la table, et de déterminer leur nécessite.

    Le script suivant va vous indiquer quelles sont les tables contenant le plus de données. Idéalement, ce script est lancé à intervalle régulier et mène à des comparaisons afin de suivre l'évolution de la base et prévoir de nouvelles actions (Merci à Greg Robidoux pour le script).

    BEGIN try  
    DECLARE @table_name VARCHAR(500) ;  
    DECLARE @schema_name VARCHAR(500) ;  
    DECLARE @tab1 TABLE( 
            tablename VARCHAR (500) collate database_default 
    ,       schemaname VARCHAR(500) collate database_default 
    );  
    DECLARE  @temp_table TABLE (     
            tablename sysname 
    ,       row_count INT 
    ,       reserved VARCHAR(50) collate database_default 
    ,       data VARCHAR(50) collate database_default 
    ,       index_size VARCHAR(50) collate database_default 
    ,       unused VARCHAR(50) collate database_default  
    );  
    
    INSERT INTO @tab1  
    SELECT t1.name 
    ,       t2.name  
    FROM sys.tables t1  
    INNER JOIN sys.schemas t2 ON ( t1.schema_id = t2.schema_id );    
    
    DECLARE c1 CURSOR FOR  
    SELECT t2.name + '.' + t1.name   
    FROM sys.tables t1  
    INNER JOIN sys.schemas t2 ON ( t1.schema_id = t2.schema_id );    
    
    OPEN c1;  
    FETCH NEXT FROM c1 INTO @table_name; 
    WHILE @@FETCH_STATUS = 0  
    BEGIN   
            SET @table_name = REPLACE(@table_name, '[','');  
            SET @table_name = REPLACE(@table_name, ']','');  
    
            -- make sure the object exists before calling sp_spacedused 
            IF EXISTS(SELECT OBJECT_ID FROM sys.objects WHERE OBJECT_ID = OBJECT_ID(@table_name))
            BEGIN 
                    INSERT INTO @temp_table EXEC sp_spaceused @table_name, false ; 
            END 
             
            FETCH NEXT FROM c1 INTO @table_name;  
    END;  
    CLOSE c1;  
    DEALLOCATE c1;  
    SELECT t1.* 
    ,       t2.schemaname  
    FROM @temp_table t1  
    INNER JOIN @tab1 t2 ON (t1.tablename = t2.tablename ) 
    ORDER BY  schemaname,tablename; 
    END try  
    BEGIN catch  
    SELECT -100 AS l1 
    ,       ERROR_NUMBER() AS tablename 
    ,       ERROR_SEVERITY() AS row_count 
    ,       ERROR_STATE() AS reserved 
    ,       ERROR_MESSAGE() AS data 
    ,       1 AS index_size, 1 AS unused, 1 AS schemaname  
    END catch

    Si dans votre modèle métier certaines tables sont conséquemment lourdes, vous devriez considérer leurs accès avec précaution (Cache, Indexes, Nolock, Types de SELECT, etc.). Pour le modèle Core par défaut, la table la plus lourde reste bien souvent la table EventLogs sur un site à fort traffic, car DotNetNuke, très intelligemment, stocke dans cette table toutes les interactions des visiteurs et les organise par type. D'autres modules stockent tout ce qui se passe et deviennent vite encombrants (DMX de Bring2Mind par exemple).

    Voilà un exemple de résultat retourné par le script dont j'ai masqué le nom des tables :
    tableName row_count reserved data index_size unused schemaname
    Table 1 17 48 KB 24 KB 24 KB 0 KB dbo
    Table 2 1478462 788560 KB 788528 KB 8 KB 24 KB dbo
    Table 3 12023 1160 KB 1096 KB 8 KB 56 KB dbo
    Table 4 12024 1224 KB 1160 KB 8 KB 56 KB dbo
    Table 5 14314 1608 KB 1552 KB 8 KB 48 KB dbo
    Table 6 12559 1288 KB 1256 KB 8 KB 24 KB dbo
    Table 7 12773 1288 KB 1280 KB 8 KB 0 KB dbo
    Table 8 13067 1352 KB 1304 KB 8 KB 40 KB dbo
    Table 9 12688 1736 KB 1696 KB 8 KB 32 KB dbo
    Table 10 463441 60744 KB 60720 KB 8 KB 16 KB dbo
    Table 11 1812 1160 KB 1136 KB 8 KB 16 KB dbo
    Table 12 266 40 KB 16 KB 24 KB 0 KB dbo
    Table 13 19836 6600 KB 6544 KB 8 KB 48 KB dbo
    Table 14 522786 39112 KB 39088 KB 8 KB 16 KB dbo
    Table 15 5 32 KB 8 KB 24 KB 0 KB dbo
    Table 16 479530 87240 KB 87224 KB 8 KB 8 KB dbo
    Table 17 0 0 KB 0 KB 0 KB 0 KB dbo
    Table 18 106300 21584 KB 19184 KB 2304 KB 96 KB dbo
    Table 19 178923 33168 KB 29088 KB 3776 KB 304 KB dbo
    Table 20 182361 31624 KB 31600 KB 8 KB 16 KB dbo
    Table 21 1510703 409136 KB 303696 KB 102264 KB 3176 KB dbo
    Table 22 1517593 305736 KB 305176 KB 8 KB 552 KB dbo
    Table 23 1270456 319176 KB 319112 KB 8 KB 56 KB dbo
    Table 24 77424 9352 KB 9328 KB 8 KB 16 KB dbo
    Table 25 12023 1480 KB 1424 KB 8 KB 48 KB dbo
    Table 26 0 0 KB 0 KB 0 KB 0 KB dbo
    Table 27 34188 6152 KB 6080 KB 8 KB 64 KB dbo
    Table 28 24049 4232 KB 4168 KB 8 KB 56 KB dbo
    Table 29 1116 704 KB 240 KB 8 KB 456 KB dbo
    Table 30 21 16 KB 8 KB 8 KB 0 KB dbo
    Table 31 19 16 KB 8 KB 8 KB 0 KB dbo
    Table 32 645484 99792 KB 36048 KB 62320 KB 1424 KB dbo
    Table 33 121 32 KB 8 KB 24 KB 0 KB dbo
    Table 34 17080 2760 KB 2272 KB 368 KB 120 KB dbo
    Table 35 451358 59400 KB 59392 KB 8 KB 0 KB dbo
    Table 36 7563 1608 KB 1568 KB 8 KB 32 KB dbo
    Table 37 435536 57160 KB 57088 KB 8 KB 64 KB dbo
    Table 38 4268 1040 KB 872 KB 136 KB 32 KB dbo

    On peut voir que les efforts devront se concentrer sur "Table 2", "Table 21", "Table 22", "Table 23", et les vues, fonctions, indexes et procédures stockées associées.
            
    Une fois votre analyse terminée et avant de supprimer les données, vous pourrez sauvegarder vers des dumps l'ensemble de la base de données via la commande SQL Management Studio > Tâches > Sauvegarder ou à l'aide du script suivant : 

    BACKUP DATABASE [Inscrivez ici le nom de la base de données] 
    TO  DISK = N'Inscrivez ici le nom complet du fichier. Ex : C:\Sauvegarde.bak' 
    WITH NOFORMAT
    	, NOINIT
    	, NAME = N'Inscrivez ici le nom interne du jeu de sauvegarde. Ex : MaBase-Backup2010'
    	, SKIP
    	, NOREWIND
    	, NOUNLOAD
    	,  STATS = 30
    GO
    

    Effacer les logs du site


    Pour effacer les logs, connectez-vous en Admin ou Hôte, et rendez-vous dans Admin > Observateur d’évènements, puis cliquez sur Effacer les logs. Il n'est pas rare de trouver plusieurs centaines de milliers de logs inutiles dans cette zone là.

    Certaines sociétés auront cependant l'obligation légale de conserver certains logs, comme les connexions au site. Pour ce faire, le script suivant va vous permettre de supprimer les logs les moins importants et de conserver en base ceux dont vous aurez choisi le type.

    DELETE FROM dbo.EventLog 
    WHERE LogTypeKey NOT IN ('LogTypeKey de votre choix','Deuxième LogTypeKey de votre choix','et ainsi de suite')


    Pour composer vous même votre "package" de logs à conserver, voici le détail des LogTypeKey (à gauche) que vous pouvez saisir, ainsi que leur description (à droite) : 

    ADMIN_ALERT Admin Alert
    APPLICATION_END Application Ended
    APPLICATION_SHUTTING_DOWN Application Shutting Down
    APPLICATION_START Application Started
    AUTHENTICATION_CREATED Authentication system created
    AUTHENTICATION_DELETED Authentication system deleted
    AUTHENTICATION_UPDATED Authentication system updated
    AUTHENTICATION_USER_CREATED User authentication added
    AUTHENTICATION_USER_DELETED User authentication deleted
    AUTHENTICATION_USER_UPDATED User authentication updated
    CACHE_DEPENDENCYCHANGED Cache Item Dependency Changed
    CACHE_ERROR Cache Error
    CACHE_EXPIRED Cache Item Expired
    CACHE_OVERFLOW Cache Item Overflow
    CACHE_REFRESH Cache Refresh
    CACHE_REMOVED Cache Item Removed
    CACHE_UNDERUSED Cache Item Underused
    DEBUG Debug Info
    DESKTOPMODULE_CREATED Desktop module created
    DESKTOPMODULE_DELETED Desktop module deleted
    DESKTOPMODULE_UPDATED Desktop module updated
    DESKTOPMODULEPERMISSION_CREATED Desktop module permission created
    DESKTOPMODULEPERMISSION_DELETED Desktop module permission deleted
    DESKTOPMODULEPERMISSION_UPDATED Desktop module permission updated
    FOLDER_CREATED Folder created
    FOLDER_DELETED Folder deleted
    FOLDER_UPDATED Folder updated
    GENERAL_EXCEPTION General Exception
    HOST_ALERT Host Alert
    HOST_SETTING_CREATED Host setting created
    HOST_SETTING_DELETED Host setting deleted
    HOST_SETTING_UPDATED Host setting updated
    LANGUAGE_CREATED Language created
    LANGUAGE_DELETED Language deleted
    LANGUAGE_UPDATED Language updated
    LANGUAGEPACK_CREATED Language pack created
    LANGUAGEPACK_DELETED Language pack deleted
    LANGUAGEPACK_UPDATED Language pack updated
    LANGUAGETOPORTAL_CREATED Language created on portal
    LANGUAGETOPORTAL_DELETED Language deleted on portal
    LANGUAGETOPORTAL_UPDATED Language updated on portal
    LISTENTRY_CREATED List entry created
    LISTENTRY_DELETED List entry deleted
    LISTENTRY_UPDATED List entry updated
    LOG_NOTIFICATION_FAILURE Log Notification Failure
    LOGIN_FAILURE Login Failure
    LOGIN_SUCCESS Login Success
    LOGIN_SUPERUSER Login - Superuser
    LOGIN_USERLOCKEDOUT User Locked Out
    LOGIN_USERNOTAPPROVED User Not Approved
    MODULE_CREATED Module Created
    MODULE_DELETED Module Deleted
    MODULE_LOAD_EXCEPTION Module Load Exception
    MODULE_RESTORED Module Restored
    MODULE_SENT_TO_RECYCLE_BIN Module Sent to Recycle Bin
    MODULE_SETTING_CREATED Module setting created
    MODULE_SETTING_DELETED Module setting deleted
    MODULE_SETTING_UPDATED Module setting updated
    MODULE_UPDATED Module Updated
    PACKAGE_CREATED Package created
    PACKAGE_DELETED Package deleted
    PACKAGE_UPDATED Package updated
    PAGE_LOAD_EXCEPTION Page Load Exception
    PASSWORD_SENT_FAILURE Password Sent Failure
    PASSWORD_SENT_SUCCESS Password Sent Success
    PERMISSION_CREATED Permission created
    PERMISSION_DELETED Permission deleted
    PERMISSION_UPDATED Permission updated
    PORTAL_CREATED Portal Created
    PORTAL_DELETED Portal Deleted
    PORTAL_SETTING_CREATED Portal setting created
    PORTAL_SETTING_DELETED Portal setting deleted
    PORTAL_SETTING_UPDATED Portal setting updated
    PORTALALIAS_CREATED Portal alias created
    PORTALALIAS_DELETED Portal alias deleted
    PORTALALIAS_UPDATED Portal alias updated
    PORTALDESKTOPMODULE_CREATED Portal desktop module created
    PORTALDESKTOPMODULE_DELETED Portal desktop module deleted
    PORTALDESKTOPMODULE_UPDATED Portal desktop module updated
    PORTALINFO_CREATED Portal info created
    PORTALINFO_DELETED Portal info deleted
    PORTALINFO_UPDATED Portal info updated
    PROFILEPROPERTY_CREATED Profile property created
    PROFILEPROPERTY_DELETED Profile property deleted
    PROFILEPROPERTY_UPDATED Profile property updated
    ROLE_CREATED Role Created
    ROLE_DELETED Role Deleted
    ROLE_UPDATED Role Updated
    SCHEDULE_CREATED Schedule created
    SCHEDULE_DELETED Schedule deleted
    SCHEDULE_FIRED_FROM_EVENT Event Schedule Started
    SCHEDULE_UPDATED Schedule updated
    SCHEDULER_EVENT_COMPLETED Scheduler Event Completed
    SCHEDULER_EVENT_FAILURE Scheduler Event Failure
    SCHEDULER_EVENT_PROGRESSING Scheduler Event Progressing
    SCHEDULER_EVENT_STARTED Scheduler Event Started
    SCHEDULER_EXCEPTION Scheduler Exception
    SCHEDULER_SHUTTING_DOWN Scheduler Shutting Down
    SCHEDULER_STARTED Scheduler Started
    SCHEDULER_STOPPED Scheduler Stopped
    SEARCH_INDEXER_EXCEPTION Search Indexer Exception
    SKINCONTROL_CREATED Skin control created
    SKINCONTROL_DELETED Skin control deleted
    SKINCONTROL_UPDATED Skin control updated
    SKINPACKAGE_CREATED Skin package created
    SKINPACKAGE_DELETED Skin package deleted
    SKINPACKAGE_UPDATED Skin package updated
    TAB_CREATED Tab Created
    TAB_DELETED Tab Deleted
    TAB_ORDER_UPDATED Tab order updated
    TAB_RESTORED Tab Restored
    TAB_SENT_TO_RECYCLE_BIN Tab Sent to Recycle Bin
    TAB_UPDATED Tab Updated
    TABMODULE_CREATED Tab module created
    TABMODULE_DELETED Tab module deleted
    TABMODULE_SETTING_CREATED Tab module setting created
    TABMODULE_SETTING_DELETED Tab module setting deleted
    TABMODULE_SETTING_UPDATED Tab module setting updated
    TABMODULE_UPDATED Tab module updated
    TABPERMISSION_CREATED Tab permission created
    TABPERMISSION_DELETED Tab permission deleted
    TABPERMISSION_UPDATED Tab permission updated
    USER_CREATED New User
    USER_DELETED User Deleted
    USER_ROLE_CREATED User Role Created
    USER_ROLE_DELETED User Role Deleted
    USER_ROLE_UPDATED User Role Updated
    USER_UPDATED User updated

    Ainsi, si vous souhaitez effacer la liste des logs en excluant les logs qui concernent les utilisateurs, vous exécuterez :

    DELETE 
    FROM    dbo.EventLog
    WHERE   LogTypeKey NOT IN ( 
    	 'LOGIN_FAILURE'
    	, 'LOGIN_SUCCESS'
    	, 'LOGIN_SUPERUSER'
    	, 'LOGIN_USERLOCKEDOUT'
    	, 'LOGIN_USERNOTAPPROVED'
    	, 'PASSWORD_SENT_FAILURE'
    	, 'PASSWORD_SENT_SUCCESS'
    	, 'USER_CREATED'
    	, 'USER_DELETED'
    	, 'USER_UPDATED'
     )
    
    

    Forcer la mise à jour de l'index du moteur de recherche

    Je me suis penché sur la question car dans le cadre d'une procédure de maintenance nocturne à heure fixe, nos processus de backup prenaient plus de temps que prévu et parfois notre index de recherche était incomplet sur plusieurs jours. Il s'avère que notre tâche planifiée mettant à jour l'index de recherche du site s'est soudain mise à durer beaucoup plus longtemps que prévu. Censée durer 2 heures maximum, elle nécessitait alors 4 à 5 heures. Cherchant la cause possible d'un tel cafouillage, je me suis aperçu que rien ne vaut une remise à zéro des indexes une fois de temps en temps. L'index est de toute façon régénéré à chaque fois... mais le vider permet d'épargner la comparaison entre l'ancien index et le nouvel index réalisé par DotNetNuke : Si un mot est indexé, alors il le met à jour, sinon, il le créé. Dans notre cas, la création est beaucoup plus rapide que la mise à jour. Voici donc un script SQL qui peut être joué avant chaque mise à jour de l'index. 

    La mise à jour de l'index de recherche constitue une tâche planifiée (Hôte > Tâches planifiées ou Host > Schedule). Vous trouverez donc dans ce menu plus d'information si vous souhaitez mettre en place un job routinier.



    Le modèle de données dédié à la recherche dans DotNetNuke est le suivant (peut être retrouvé sur le modèle de données en ligne) : 



    Pour exécuter le script, rendez-vous sur le menu Hôte > SQL, cochez "Lancer un script", puis avant de cliquer sur "Exécuter", collez dans la zone de texte le script suivant : 

    TRUNCATE TABLE {databaseOwner}{objectQualifier}SearchItemWordPosition 
    DELETE {databaseOwner}{objectQualifier}SearchItemWord 
    DELETE {databaseOwner}{objectQualifier}SearchWord 
    DELETE {databaseOwner}{objectQualifier}SearchItem

    Défragmenter les fichiers du site,  les fichiers de la base de données et ses indexes

    La fragmentation des fichiers d'un disque est un phénomène naturel qui relève l'âge des fichiers. Les séquences des fichiers sont placées puis déplacées et finalement le disque dur doit accéder à plusieurs endroits pour lire un seul et même fichier. Pour y remédier, il existe le défragmenteur de fichiers de Windows, qui fonctionne très bien, ou des utilitaires professionnels comme Diskeeper. Pour un meilleur résultat, prévoyez une défragmentation au cours de laquelle vous aurez préalablement arrêté les services qui occupent les fichiers que vous voulez défragmenter (SQL Server par exemple).

    La fragmentation des indexes de la base revêt un caractère plus complexe et crucial. Si vous vous êtes déjà dit : "Avant lorsque j'entrais sur cette page d'édition c'était beaucoup plus rapide", ce paragraphe est fait pour vous. La suite est un petit peu technique et en anglais : ola.hallengren.com mais pour faire bref, téléchargez le script SQL sur CodePlex, puis ouvrez le à l'aide de SQL Server Management Studio. Connectez-vous et éxécutez le script. Attention : Le script, par défaut, va défragmenter tous les indexes de toutes les bases présentes sur le serveur et installer un travail répétitif qui s’exécutera tout seul pour sauvegarder vos bases et les défragmenter. Ci vous ne voulez pas tout cela, mais simplement une défragmentation des indexes, extrayez les scripts de création de la procédure stockée "IndexOptimize" et de la fonction "DatabaseSelect", puis exécutez la procédure stockée "IndexOptimize". Si vous ne savez pas comment faire, vous pouvez exécuter sur votre base DotNetNuke le script suivant : DatabaseSelect_IndexOptimize.sql

    ... puis exécuter ce script ci (remplacez les deux NOMDELABASE par le nom de la base de données de votre instance DotNetNuke). 

    USE [NOMDELABASE]
    GO
    
    DECLARE	@return_value int
    
    EXEC	@return_value = [dbo].[IndexOptimize]
    		@Databases = N'NOMDELABASE',
    		@FragmentationHigh_LOB = 'INDEX_REBUILD_OFFLINE' ,
    		@FragmentationHigh_NonLOB = 'INDEX_REBUILD_OFFLINE' ,
    		@FragmentationMedium_LOB = 'INDEX_REORGANIZE' ,
    		@FragmentationMedium_NonLOB = 'INDEX_REORGANIZE' ,
    		@FragmentationLow_LOB  = 'NOTHING' ,
    		@FragmentationLow_NonLOB = 'NOTHING' ,
    		@FragmentationLevel1 = 5 ,
    		@FragmentationLevel2 = 30 ,
    		@PageCountLevel = 1000 ,
    		@SortInTempdb = 'N' ,
    		@MaxDOP = NULL ,
    		@FillFactor = NULL ,
    		@LOBCompaction = 'Y' ,
    		@StatisticsSample = NULL ,
    		@PartitionLevel = 'N' ,
    		@TimeLimit = NULL ,
    		@Indexes = NULL ,
    		@PadIndex = NULL ,
    		@Execute  = 'Y'
    		
    
    SELECT	'Return Value' = @return_value
    
    GO
    

    Le script va retourner une valeur 0, qui indique que les indexes ont été défragmentés. Si vous exécutez le script une nouvelle fois, il s’exécutera plus rapidement (le script a nécessité 3 minutes sur ma base d'exemple, un site DotNetNuke mis à jour depuis DNN 4.1 et visité quotidiennement par plusieurs centaines d'utilisateurs).

    Placer la base de données sur un disque plus rapide et indépendant


    Si vous disposez de plusieurs disques dur physiques sur votre serveur, il serait judicieux de considérer d'en dédier un à la base de données. Pour ce faire, ouvrez SQL Server Management Studio, et déplacez les fichiers de la base sur ce disque dur.
    La procédure est assez simple ; accédez aux Propriétés de la base de données que vous voulez déplacer afin de connaître son emplacement sur le disque dur. Détachez ensuite la base en accèdant au menu Tâches > Détacher. Déplacez ensuite les ficheirs LDF et MDF sur votre nouveau disque dur. Enfin, rattachez la base à son nouvel emplacement en accèdant au menu Tâches > Attacher.

    Optimiser les paramètres de cache dans la configuration Hôte


    La configuration du cache et des performances dans DotNetNuke se résume à peu près à la compréhension de ce screenshot de la section Performances de la page Hôte > Paramètres de l'hôte. J'ai en effet décidé d'inclure dans notre pack de langue une aide beaucoup plus complète que le pack de langue "original" que nous construisions déjà sur dnn.fr. Notre pack de langue peut être téléchargé sur la page d'accueil.




    Utiliser le bon cache dans vos modules personnalisés (Cache session, cache SQL, cookie, etc.)


    Lorsque vous développez des modules, n'oubliez pas qu'un certain nombre de contenus peuvent être mis en cache. Cela peut concerner le résultat d'un traitement qui ne variera pas ou peu dans le temps, un contexte utilisateur qui fera office de constante pour toute la durée de la session, etc. Des objets entiers peuvent être "mis en cache", raccourcissant d'autant la génération de la réponse HTTP.

    Voici comment utiliser les différents caches et l'usage qui est généralement réservé à chacun.

    Le Cache ASP.Net :
    Le cache ASP.Net est utilisé pour stocker des données complexes. Stocké sur le serveur, il est réutilisable tout le temps. Il se vide au recyclage du Pool Applicatif. On l'utilise généralement pour stocker le résultat de requêtes volumineuses qu'on ne souhaite pas lancer à tout va, ou encore pour partager des données mises en cache entre plusieurs utilisateurs.
    Ajouter / Editer
    Cache("CléAccesseurDeLObjet") = objMonObjet

    Supprimer
    Cache.Remove("CléAccesseurDeLObjet") 

    Obtenir la valeur
    objMonObjet = Cache("CléAccesseurDeLObjet")

    Le Cache Session
    Le cache Session est utilisé pour stocker des données propre à chaque utilisateur : un panier eShopping, un profil, etc. Les données sont stockées sur le serveur, et une clé est stockée chez le client dans un cookie permettant d'identifier la session concernée par les appels. Si le client ferme la fenêtre de son navigateur, la session est généralement perdue. La session est également détruite après 20 minutes d'inactivité, par défaut (Cf. pouvant être spécifié dans la configuration de IIS).
    Ajouter / Editer
    Session("CléAccesseurDeLObjet") = objMonObjet

    Supprimer
    Session.Contents.Remove("CléAccesseurDeLObjet") 

    Obtenir la valeur
    objMonObjet = Session("CléAccesseurDeLObjet")

    Le cache ViewState
    Le cache ViewState est utilisé pour stocker des données d'un PostBack à un autre. Les données sont stockées dans un champ caché accessible au navigateur web. Le ViewState ne peut que stocker des String ou des objets sérialisables, et son usage peut être forcé à false sur certains contrôles ASP.Net grâce à l'attribut "EnableViewState" à false.
    Ajouter / Editer
    ViewState("CléAccesseurDeLObjet") = objMonObjet

    Supprimer
    ViewState.Remove("CléAccesseurDeLObjet") 

    Obtenir la valeur
    objMonObjet = ViewState("CléAccesseurDeLObjet")



    Vous avez d'autres astuces ? N'hésitez pas à les publier sur le forum ou à créer un nouvel article.

     

    Notez cet article !

    DotNetNuke c'est ...

    • Facile à utiliser
    • Open Source et gratuit
    • 100% personnalisable
    • Des milliers d'extensions
    • Multilingue
    • Multi-site
    • Maintenu par une communauté d'experts
    • Sécurisé

    Restez informé !

    Inscrivez vous pour recevoir notre lettre d'information.

    x

    Restez connecté !

    Le fichier que vous téléchargez sera probablement mis à jour très bientôt.

    Inscrivez vous
    et nous vous informerons des mises à jour