lundi 31 août 2009

SqlServeur training - Maintaining Sql2008 database - Jour 1

Cette fois, ce training est orienté administration de sql serveur 2005/2008.
Cette journée a été consacrée a l'installation/upgrade de sql serveur et la gestion des DB et fichiers.
Voici ce que j'ai plus particulièrement retenu de cette journée.

Ne soyez pas choqué par mes largesses avec la langue française, ces notes sont rédigées à la volée à partir d'un cours en anglais.

Utilisation de plusieurs instances
Il est possible d'installer plusieurs instances de Sql Serveur sur une même machine.
Cela permet d'avoir un environnement de test entièrement distinct d'un environnement de production (sans pour autant avoir besoin d'un second serveur sql).
Les différentes instances installées sur un même serveur n'ont a proprement parlé "rien en commun" (ou presque).

Conseil de mise-à-jour
Plutôt que de faire une mise-à-jour "in-place" d'un serveur de production il est vivement recommandé de faire une mise-à-jour "side-by-side".
Ainsi donc, le nouveau serveur SQL fonctionnera comme une seconde instance sur le même serveur.
Les bases de données peuvent alors êtres migrées une par une vers la nouvelle instance de Sql serveur.
Cela évite de se trouver dans la situation genante ou l'une des DB ne fonctionne pas correctement sur la nouvelle installation et ou il faut tout restaurer en catastrophe dans l'ancien environnement.
Conséquences de l'upgrade side-by-side:
Les connections string des applications doivent être modifiés pour attaquer la nouvelle instance de serveur SQL, c'est à dire, Serveur name + Instance name (ce n'est pas toujours aisé suivant le logiciel).
Etant donné qu'il n'est pas possible de renommer une instance de Sql Serveur, une fois toutes les DB de l'ancienne instance de Sql Serveur migrées, on pourra désinstaller cette instance mais en aucun cas renommer la nouvelle instance. Choississez bien le nom de vos instances :-)

Aide à la mise-à-jour
Si l'on installe une nouvelle version de Sql serveur, ces outils ne sont pas utiles. Par contre, en cas de mise-à-jour, il est vivement conseillé d'utiliser ces outils lors de phase de mise à jour de sql serveur.

Upgrade Advisor
Avant de faire une mise-à-jour, il est possible d'installer le "Upgrade Advisor" de Microsoft sur la machine.
Ce dernier liogiciel disponible sur le DVD d'installation de Sql2008 permet de faire toute une série de vérification sur les schéma des DB et d'en obtenir une série de recommandations.
Cet outil est à utiliser avant et après une mise-à-jour Sql Serveur.

Upgrade Assitant (**)
Cet outil créé par des anciens de Microsoft est disponible sur le net à http://www.scalabilityexperts.com/.
Plus difficile a installer (car demandant une étape de configuration plus poussée), cet outil est bien plus complet que l'upgrade Advisor.
En effet, en plus d'analyser les schémas pour fournir des recommandations, cet outil capture également les Sql exécutés sur la DB à migrer pour ensuite les tester sur la DB target (nouvelle version de Sql Serveur).
Cet outil permettra d'identifier les éléments causant des problèmes lors de la migration (comme pertes de performances ou consommations de ressources).

Sql Serveur 2005 Surface Area Configuration
Lorsque l'on installe une nouvelle version de Sql serveur, tous les paramètres par défaut qui sont appliqués ne sont pas succeptible de provoquer des problèmes de sécurités. Par exemple, l'accès DAC, le CLR, XP_CmdShell et Ole Automation sont des fonctionnalités désactivées par défaut.
Par contre, lors d'une mise-à-jour, les paramètres Sql présents sur le système sont conservés et sont par conséquent des sources de problèmes de sécurité plus ou moins grave selon la situation.
C'est là qu'intervient le Surface Area Configuration de sql serveur 2005.
Cet outil disponible depuis le start menu (section Sql Serveur) présente toutes les "options" à risque avec la configuration actuelle ainsi qu'une description.
C'est également via cet outil que l'on active des options comme l'utilisation du CLR (.Net engine pour créer des fonction/trigger/stored proc dans sql serveur).
Pour Sql Serveur 2008, cet outil n'est plus disponible via le start menu mais reste accessible via l'import et l'évaluation du fichier "c:\program files\Microsoft sql server\100\tools\policies\database engine\1033\Surface Area Configuration *.xml" dans le Policy Management tools du management studio. 

Outils administratifs / maintenances
Sql 2005 BPA (best practice Advisor)
Cet utilitaire disponible en libre téléchargement depuis le site de Microsoft permet de faire une analyse de type "best practice" sur une base de donnée.
De cette analyse découle un rapport avec des recommandations. Cet outil devrait être utilisé de façon régulière afin de détecter les points faibles d'une configuration.
Au rang des vérifications l'on retrouve:
  • Vérification des settings de sécurité.
  • Vérification des "naming conventions".
  • Vérification des derniers backups (et quand).
  • Vérification des collations.
  • Vérification de la dernière exécution de DBCC (check intégrity).
Pour sql serveur 2008 cet outil est disponible depuis le management console.

System Configuration Manager (**)
En suivant les recommandations de Microsoft, on utilisera cet outil pour modifier la configuration des services de sql serveur.
Cet outil présente un arbre énumerant les différentes instances et services (database engine, reporting engine, integration service, etc) de Sql Serveur.
A partir de cet arbre, il est en autre possible de modifier le compte NT utilisé pour faire fonctionner l'un ou l'autre des services de sql serveur. Ce qu'il y a de bien avec cet outil, c'est qu'il adapte également les crédentials de l'utilisateur NT (celui faisant fonctionner le service) pour faire fonctionner correctement le service sql.
Cet outil permet également d'activer et configurer 

Policy Management (**)
Sql serveur 2008 dispose d'un outil de management des policies.
Ces policies permettent de construire des conditions vérifiables sur les objets sql (ou une partie de ceux-ci ... comme les tables d'une DB particulière).
Par exemple, s'assurer que toutes les views aient un nom commencant par "v" ou toutes les stored procedures ayant un nom commencant par "usp".
Ce module permet de construire des conditions très complexes.
Les policies peuvent êtres:
  •  Evaluées dans le but de fournir un rapport.
  • Contraignantes: empêchant la création de l'objet si la vérification de la condition échoue.
  • Non contraignantes: l'objet est créé mais le système enregistre un événement dans le log sql.
Configuration de l'option serveur ANSI NULL
A l'instar de DB2 ou Oracle, par défaut, Sql Serveur ne suis pas le standard ANSI Sql en ce qui concerne l'évaluation NULL (c'est la seule entorse de sql serveur par rapport au standard ANSI car suivre ce standard coûte beaucoup plus cher en temps cpu).
Pour sql serveur (en configuration par défaut), la concaténation de 'Test'+NULL donnera une valeur NULL. Ce qui n'est pas le cas de langages évolués comme Java ou la concaténation de 'DB'+NULL produit le résultat 'DB' ou encore des DB comme oracle. 
Il n'est donc pas rare de voir de développeur modifier l'option ANSI NULL de sql serveur pour qu'il corresponde a leur besoin. 
C'est une option à vérifier attentivement lors de l'installation d'une DB car elle est la source fréquente de problèmes.

our les produits fonctionnant sous Oracle/DB2 ou sql serveur.

dimanche 30 août 2009

Installer une imprimante HP1005P sur Ubuntu 8.04

Nous venons juste d'acheter une imprimante laser Hp pour la modique somme de 75€.
Après installation de cette imprimante sur notre PC famillial Ubuntu, cette dernière n'imprime absolument rien même si elle est reconnue et semble fonctionner correctement (d'un point de vue logiciel/printer spooler).

La cause
En jetant un petit coup d'oeil dans les journaux système, l'on se rend compte que les pilotes Hp installés sur Ubuntu 8.04 ne disposent pas d'un accès sur un socket.
Le message d'erreur étant:

Aug 30 17:33:56 ubuntu-x HP_LaserJet_P1005?serial=BC19XWG: prnt/backend/hp.c 496: unable to connect hpssd socket 2207: Connection refused 

La solution
Ré-installer les pilotes Hp.
Il est possible de les télécharger depuis le site "HP Linux Imaging and Printing" a l'origine des librairies HPLIP.
Après quelques questions sur le système d'exploitation et l'imprimante à installer, vous être dirigés vers un téléchargement et les instructions d'installation.
J'ai suivi avec succès cette procédure qui s'est elle même chargée de la désinstallation de la précédente version.

La version d'Ubuntu
Pour accomplir cette procédure sur le site de HPLIP, il est nécessaire de connaître la version exacte de son système d'exploitation.
Sur Ubuntu, tapez la commande suivante:

cat /etc/issue

jeudi 27 août 2009

Sql Serveur: Implémenter une fonction sql en C#

Voici une référence intéressante concernant l'implémentation de code C# directement dans Sql Serveur 2005.

Voir l'article "Implement User-defined Functions in SQL Server 2005 with Managed Code" sur Developer.com

mardi 25 août 2009

Dia, un Visio version libre

Besoin de dessiner un diagramme mais pas envie d'installer Visio?
Dia se présente alors comme une alternative intéressante... jetez donc un oeil sur cette page d'exemple.
En plus d'être gratuit, Dia dispose aussi d'un module de scripting an Python.

Il est également possible de trouver des formes complémentaires pour Dia.
Un catalogue des formes est disponible depuis la page de présentation de Dia sur le site de Gnome.

lundi 24 août 2009

Python - Quelques références

Voici quelques références utiles pour utiliser Python (en autre sous Windows).
Documentation

Google App Engine - en savoir plus en vidéo

Voici une série de vidéos collectées sur YouTube autour de Python et de Google App Engine, le tout regroupé par thème. Plus de vidéo sur la playlist YouTubes: Google App Engine


Google AppEngine (CampFire)
Trois vidéos d'introduction à Google App Engine






Painless Python
En deux parties




Google App Engine
Plus d'informations autour de App Engine

Developing and deploying an application on Google App Engine


App Engine Datastore Under the Covers (Google IO 2008)



Building Quality Apps on App Engine (Google IO 2008)



Managing your App Engine app with the admin console (ok)



Getting Started with App Engine in Eclipse


Becoming a Google Apps Solution provider (Google IO 2008)



Google App Samples

Addressbook: A walkthrough of a simple AppEngine application (ok)


Pix chat on Google App Engine

jeudi 20 août 2009

Test systematique des locks Sql (primary key design)

Voila un article qui sort également de mon grenier.
Entamé en janvier 2009, je n'ai jamais eu l'occasion de pendre le temps nécessaire à son parachèvement.


Introduction
Une table avec un mauvais design (1*) ou ne disposant pas d'index approprié peut vite devenir un véritable goulot d'étranglement.
Si certains index manquent, SQL server sera amené à poser des locks de façon inconsidéré sur les records durant les opérations de lecture (et ce afin de limiter les accès concurrents au moindre coût pour Sql Serveur).
Si le design n'est pas correct, pour une table de 100.000 enregistrements, un simple SELECT peut temporairement engendrer quelques 30.000 locks... et même sur les pages d'index (cas pour l'exemple 1*) ce qui ralentira considérablement les autres processus voulant accéder cette même ressource (la table).
C'est ainsi que par le passé, une simple requête SQL sur une table contenant des  signatures prenait de 5 à 15 secondes (avec même des timed-out ADO en cas de requêtes concurrentes).
Une simple modification de design et l'utilisation d'un index approprié a ramené ce temps entre 0 et 30 milli-secondes.

Ce qu'il faut savoir:
  1. C'est que les locks induits par un mauvais design de table peuvent avoir des conséquences importantes sur les ressources SQL. Dans ce cas, SQL serveur peut être amené à manipuler des dizaines de milliers de locks pour satisfaire les différentes requêtes.
    Cela ce traduit par une lenteur excessive SQL, un CPU SQL > 60%. La stored procedure sp_locks retournant dans ce cas plusieurs dizaines de milliers d'entrées... dont la plupart ne concernant qu'un seul objet (comprenez "table").
    Il est aisé d'identifier et cerner ce problème, un simple sp_lock faisant apparaître l'évidence.
  2. C'est que certains mécanismes de lockings n'apparaîtrons qu'en accès concurrents... lorsque les mécanismes de locking s'escaladeront les uns sur les autres.
    Par exemple, la simple exécution d'une variante d'un même SQL depuis plusieurs threads peut créer cette situation de locking (entre 500 et 1500 locks, voir plus).... alors qu'à contrario, l'exécution unique de la même requête ne révélera absolument rien.
    En soit, c'est moins grave... cela rends seulement la détection des locks en accès concurrents plus difficile (par exemple plusieurs personnes accèdent en même temps une même page sur un site web).

1*) Un exemple de mauvais design: La primary key
Un exemple typique de mauvais design est l'utilisation d'une "Clustered Primary Key" sur un champ unique contenant  une valeur incrémentée.
C'est le cas des tables utilisant un ID unique comme identifiant... cas largement
répandu dans l'industrie.
Ce point fera l'objet d'un article plus approfondit.

Test systématique des locks
Le test systématique des locks à l'aide de perfMon durant les phases de tests soutenues (alpha ou en charge) permet de suivre l'évolution (l'escalade) des locks durant ces phases.
Ainsi, stresser une application/fenêtres/pages web (en répétition simple et/ou en séquences) tout en gardant l'oeil sur perfMon, permet de se faire une idée des conditions, problèmes et congestions potentiels en accès concurrent.
Si de surcroît le  Profiler Sql est utilisé durant cette phase, il est même possible d'identifier plus précisément les requêtes qui posent problèmes (voir temps d'exécution, nombre d'I/O, ... dans le profiler).

La première étape restant, avant tout, d'identifier visuellement les zones/séquences de l'application causant des heurts pour ensuite regarder de plus près (avec sp_locks, profiler sql).



Configurer PerfMon pour un test systématique


Etape 1: Modifier les settings du performance monitor (PerfMon)

Par défaut, le performance monitor affiche le graph avec une échelle de 0 à 100.
Il en est ainsi parce que la plupart des compteurs/traces s'expriment en % de ressources.
Dans le cas qui nous concerne, il en va tout autrement. Les traces que nous allons ajouter contiennent des valeurs absolues (du genre 120 locks ou 4312 locks).
Si l'on veut les afficher correctement, c'est à dire sans que les traces ne passent leur temps à quitter le graphique, il faudra modifier l'échelle d'affichage.
Il sera ainsi possible de suivre visuellement l'évolution les locks pour détecter quand il conviendra d'agir (par exemple quand la valeur s'élèvera au dessus de 1500 locks).

Voici donc la marche a suivre: 
Dans les propriétés du graphe, sélectionner l'onglet "Graph" et modifier la valeur Maximum.
Dans un premier temps, la valeur 2000 sera tout à fait raisonnable pour une machine de développement.
En environnement de production, ou les accès concurrents sont fréquents, une valeur Maximum de 2000 pourrait bien être insuffisant.

Etape 2: Sélectionner les traces qui seront monitorées

Ajouter une trace
 
La boite de dialogue "Add Counter" apparaît... 
Dans cette dernière, sélectionner "Lock Request/Sec".
Notez que Key, Page et RID sont sélectionnés dans la sous liste. En effet, suivant les cas, ce sera plutôt un type de lock ou l'autre qui sera utilisé par Sql serveur... dans tous les cas, l'élévation de ces locks peuvent avoir une influence majeure sur les performances de Sql Serveur.

Voici ci-dessous une liste exhaustive des locks monitorés.


Le gros défaut de cette méthode graphique


Il n'est pas possible d'identifier facilement les locks portant sur les tables TABLOCK.
En effet, il ne faut qu'un seul tablock pour bloquer une table entière alors que le graph affiche les valeurs de 0 à 2000. Autant dire que les tablocks ne sont pas visibles sur le graph puisqu'ils se confondront avec l'abscisse.
Cependant le TABLOCK reste un événement exceptionnel, Sql Serveur n'y a recours que lorsqu'il n'est pas possible de faire autrement.
Cependant, l'usage de TabLock par SQL serveur a également des conséquences catastrophiques sur les performances/temps de réponse en accès concurrent (en effet, les autres processus/requêtes accédant cette même ressource/table restent en attente).

Quand le Tablock frappe...
C'est entre autre l'événement qui nous est arrivé, un TABLOCK bloquait la primary key de notre table d'audit (19 millions de records) durant les requêtes de lecture.
Du coup, le software n'était plus capable d'insérer de nouveaux enregistrements dans l'audit trail (Gloups!) et ce pendant des périodes de 1 à 4 minutes.

Performance - Fragmentation des indexes

Introduction
Lorsque SQL serveur est en perte de performance, et que cette dernière perte de performance est associée a de nombreux Wait Time PAGEIOLATCH_* ou CX_PACKET, il convient de vérifier la fragmentation des indexes.

En effet, s'il n'y a pas de plan de maintenance pour faire une mise à jour des statitiques et une réorganisation des indexes de façon régulière, alors dans ce cas, les indexes seront de plus en plus fragmentés.
La conséquence la plus immédiate pour Sql Serveur est la sélection d'un mauvais "Execution Plan" par le query optimizer... ayant généralement comme résultat une forte augmentation des accès disques et par conséquent de faible performances Sql.

Le disque devient alors le goulot d'étranglement diminuant les performances SQL, la raison pour laquelle les Wait Time PAGEIOLATCH_*  grimpent en flèche.

Reorganisation ou Reconstruire
Reconstruction
Si l'index est fort fragmenté (>30%), il faut le reconstruire pour minimiser la fragmentation.
Reconstruire un index fait une mise-à-jour des statistiques... mais cela n'est possible "online" que pour les versions Enterprise Edition.
La reconstruction (rebuild) étant grande consommatrice de I/O on veillera a effectuer cette operation en heure creuse, même pour une Edition Enterprise.
Reorganisation
Si l'index est peu fragmenté (5% < frag% <= 30%), une simple réorganisation est suffisante. Cela consomme d'ailleurs peu de ressource et peut toujours être exécuté Online.
Par contre, cette opération ne fait pas de mise-à-jour des statistiques, il faudra donc le faire manuellement.


Détection et correction
La requête suivante examine la fragmentation des indexes et en affiche le résultat sous forme de commentaire Sql.
La requête prépare également les différentes requêtes SQL nécessaires pour corriger la situation.

Attention, l'exécution de cette requête consomme ENORMEMENT de ressources disques.

-- Ensure a USE <databasename> statement has been executed first. 
SET NOCOUNT ON; 
DECLARE @objectid int; 
DECLARE @indexid int; 
DECLARE @partitioncount bigint; 
DECLARE @schemaname nvarchar(130); 
DECLARE @objectname nvarchar(130); 
DECLARE @indexname nvarchar(130); 
DECLARE @partitionnum bigint; 
DECLARE @partitions bigint; 
DECLARE @frag float; 
DECLARE @command nvarchar(4000); 
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function 
-- and convert object and index IDs to names. 
SELECT object_id AS objectid, index_id AS indexid, 
  partition_number AS partitionnum, 
  avg_fragmentation_in_percent AS frag 
INTO #work_to_do 
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') 
WHERE 
  avg_fragmentation_in_percent > 10.0 AND 
  index_id > 0; 

-- Declare the cursor for the list of partitions to be processed. 
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do; 

-- Open the cursor. 
OPEN partitions; 

-- Loop through the partitions. 
WHILE (1=1) 
  BEGIN; 
    FETCH NEXT 
      FROM partitions 
      INTO @objectid, @indexid, @partitionnum, @frag; 
    IF @@FETCH_STATUS < 0 BREAK; 
    SELECT @objectname = QUOTENAME(o.name), 
       @schemaname = QUOTENAME(s.name) 
    FROM sys.objects AS o 
      JOIN sys.schemas as s ON s.schema_id = o.schema_id 
    WHERE o.object_id = @objectid; 

    SELECT @indexname = QUOTENAME(name) 
    FROM sys.indexes 
    WHERE object_id = @objectid AND 
      index_id = @indexid; 

    SELECT @partitioncount = count (*) 
    FROM sys.partitions 
    WHERE object_id = @objectid AND index_id = @indexid;

    print '-- Object '+@schemaname + N'.' + @objectname + ' - index '+@indexname+' - Fragmentation '+Cast( @frag as Varchar(10) )
    -- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding. 
    IF @frag < 30.0 
       SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + 
           @schemaname + N'.' + @objectname + N' REORGANIZE'; 
    IF @frag >= 30.0 
       SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + 
           @schemaname + N'.' + @objectname + N' REBUILD'; 

    IF @partitioncount > 1 
       SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10)); 

    -- Uncomment following lines to execute
    --
    -- EXEC (@command); 
    --PRINT N'Executed: ' + @command; 

    -- print command to execute
    PRINT  @command;
    PRINT  'GO;' 

  END; 
  -- Close and deallocate the cursor. 

CLOSE partitions; 
DEALLOCATE partitions; 

-- Drop the temporary table. 
DROP TABLE #work_to_do; 

GO
Autre ressources
  • Index Defrag Script est un script très complet avec plein d'options permettant de faire un traitement très pointu de défragmentation des indexes.

Lire les SqlServer logs depuis TSQL

Il est des cas où l'accès à l'interface du Console Management n'est pas disponible sur un serveur SQL donné.
Ou bien encore, le Sql Server Log est trop long pour être accédé depuis cette même interface graphique.
Dans ce cas, l'utilisation de la stored procedure sp_readerrorlog s'avère bien pratique.

Syntaxe
EXEC sp_readerrorlog Param1,Param2, Param3, Param4

Param 1: identification de l'archive (0=Current Log, 1=Archive 1, 2=Archive 2, etc)
Param 2: Type de log à lire (1 ou NULL= SqlServer Log, 2=Sql Agent Log)
Param 3: texte à rechercher dans le log.
Param 4: raffiner la recherche en cherchant un autre texte dans les résultats de Param3

Exemple
La requête suivante va lire le log courant (Param1=0) du "SqlServer log" (Param2=1) pour y rechercher le texte 'been using' (Param3='been using').
EXEC sp_readerrorlog 0,1 

Cette recherche permet d'être informer des jours de fonctionnement de SQL server. En effet, tous les jours à heure de démarrage, Sql Server affiche la ligne suivante dans le log "This instance of SQL Server has been using a process ID of xxx since ..."

Référence
Pour plus d'informations, voir l'article "Reading the SQL Server log files using T-SQL" sur MSSqlTips.

Capture et explications des Wait Times

Notes complémentaires faisant suite aux articles "SQL Server Monitoring Performance - Wait Stats" et "Utiliser le SQL Profiler pour optimiser une base de donnée" précédemment publiés.

Cet article visera principalement la définition de certains Wait Times et la présentation d'une autre méthode de capture des Wait Stats.
Commencé mi-mai, il m'aura fallut presque 3 mois pour organiser une synthèse correcte de mes recherches.

Définition des Wait Times
Sql Serveur peut encourir différents délais d'attentes sur des processus internes.
Ces délais d'attentes sont généralement les indicateurs de problèmes de performances.
En analysant de plus près les statistiques de Wait Types, il est possible d'identifier la ou les sources causant les dégradations de performances sur SQL serveur.
Les Wait Times peuvent être consultés depuis la Dynamic Management View Sys.dm_os_wait_stats.
Ces statistiques étant maintenue au niveau du serveur SQL (cumulant l'information au fur et à mesure) il est nécessaire d'effectuer plusieurs requêtes (dans le temps) et quelques opérations de soustractions pour obtenir des informations exploitables.
L'article "SQL Server Monitoring Performance - Wait Stats" écrit précédemment met en place une méthode de capture systématique des wait times toutes les minutes. Quelques scripts sql permettent également d'exploiter l'information au mieux.

Cas Pratique
Dans un cas récent, des délais importants sur le Wait Time "WRITELOG" (plusieurs secondes par minutes) nous indiquait un problème de "libre" accès au fichier de transaction sql sur les disques SAN.
Ce problème d'accès causant des temps de réponses vraiment importants (jusqu'à 30 secondes) pour les applications clientes.

Capture des Wait Types
SELECT wait_type, waiting_tasks_count, wait_time_ms, 
  max_wait_time_ms, signal_wait_time_ms 
FROM master.Sys.dm_os_wait_stats 
where wait_type like 'LogBuffer' or 
  Wait_Type like 'LOGMGR%' or 
  wait_type like 'WRITE%' or 
  wait_type like 'latch_%' or 
  wait_Type like 'IO_COMPLETION' or 
  Wait_type like 'SOS_SCH%' or
  wait_type like 'PAGEIOLATCH%' 

Reset des statistiques
DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR);

Signification de "signal_wait_time_ms"
Le champs signal wait time de sys.dm_os_wait_stats nécessite quelques explications complémentaire.
Ce temps représente le délai d'attente entre le moment où la ressource est signalée (ressource disponible) et le moment ou le thread de traitement ait été reschédulé pour l'execution.
Autrement dit le délai nécessaire pour que la tâche soit reprogrammée par le scheduler (le scheduler organise au mieux la distribution des ressources CPU aux différents processus Sql).
Sur les systèmes/schedulers chargés, le "signal_wait_time_ms" est une indication de pression sur le CPU (ressource CPU disponible de façon trop limitée pour les tâches).
Ce temps est déjà inclus dans "wait_time_ms" (ref).

This time represents the time that the actual wait event finished, and the time the task is scheduled to run on the scheduler again. On busy schedulers this signal wait time can be an indication of CPU pressure.

Monitoring de WaitStats selon Microsoft

Le SQL suivant originaire des laboratoires de Microsoft est extrait du forum de Sql Serveur Magazine. Il permet de tracker les wait stats pour Sql Serveur 2000.



if exists (select 1 from sysobjects where name = 'track_waitstats') 
drop proc track_waitstats 
go 
CREATE proc track_waitstats (@num_samples int=10,@delaynum int=1,@delaytype nvarchar(10)='minutes') 
as 
-- 
-- This stored procedure is provided "AS IS" with no warranties, and confers no rights. 
-- Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm 
-- 
-- T. Davidson 
-- @num_samples is the number of times to capture waitstats, default is 10 times 
-- default delay interval is 1 minute 
-- delaynum is the delay interval - can be minutes or seconds 
-- delaytype specifies whether the delay interval is minutes or seconds 
-- create waitstats table if it doesn't exist, otherwise truncate 
-- 
set nocount on 
if not exists (select 1 from sysobjects where name = 'waitstats') 
create table waitstats ([wait type] varchar(80), 
requests numeric(20,1), 
[wait time] numeric (20,1), 
[signal wait time] numeric(20,1), 
now datetime default getdate()) 
else truncate table waitstats 
dbcc sqlperf (waitstats,clear) -- clear out waitstats 
declare @i int,@delay varchar(8),@dt varchar(3), @now datetime, @totalwait numeric(20,1) 
,@endtime datetime,@begintime datetime 
,@hr int, @min int, @sec int 
select @i = 1 
select @dt = case lower(@delaytype) 
when 'minutes' then 'm' 
when 'minute' then 'm' 
when 'min' then 'm' 
when 'mm' then 'm' 
when 'mi' then 'm' 
when 'm' then 'm' 
when 'seconds' then 's' 
when 'second' then 's' 
when 'sec' then 's' 
when 'ss' then 's' 
when 's' then 's' 
else @delaytype 
end 
if @dt not in ('s','m') 
begin 
print 'please supply delay type e.g. seconds or minutes' 
return 
end 
if @dt = 's' 
begin 
select @sec = @delaynum % 60 
select @min = cast((@delaynum / 60) as int) 
select @hr = cast((@min / 60) as int) 
select @min = @min % 60 
end 
if @dt = 'm' 
begin 
select @sec = 0 
select @min = @delaynum % 60 
select @hr = cast((@delaynum / 60) as int) 
end 
select @delay= right('0'+ convert(varchar(2),@hr),2) + ':' + 
+ right('0'+convert(varchar(2),@min),2) + ':' + 
+ right('0'+convert(varchar(2),@sec),2) 
if @hr > 23 or @min > 59 or @sec > 59 
begin 
select 'hh:mm:ss delay time cannot > 23:59:59' 
select 'delay interval and type: ' + convert (varchar(10),@delaynum) + ',' + @delaytype + ' converts to ' + @delay 
return 
end 
while (@i <= @num_samples) 
begin 
insert into waitstats ([wait type], requests, [wait time],[signal wait time]) 
exec ('dbcc sqlperf(waitstats)') 
select @i = @i + 1 
waitfor delay @delay 
end 
select @now=max(now),@begintime=min(now),@endtime=max(now) 
from waitstats where [wait type] = 'TOTAL' 
--- subtract waitfor, sleep, and resource_queue from Total 
select @totalwait = sum([wait time]) + 1 from waitstats 
where [wait type] not in ('WAITFOR','SLEEP','RESOURCE_QUEUE','TOTAL', '***total***') and now = @now 

-- insert adjusted totals, rank by percentage descending 
insert into waitstats select '***total***',0,@totalwait,@totalwait,@now 
select 'start, end, duration'='start: ' + convert(varchar(20),@begintime,20) + ' end: ' + convert(varchar(20),@endtime,20) + ' duration (minutes): ' + convert(varchar(10), datediff(mi,@begintime,@endtime)) 
select 'waitstats samples'=@num_samples, 'delay, type'= convert (varchar(10),@delaynum) + ',' + @delaytype,'waitfor delay interval'=@delay 
select [wait type],[wait time],percentage=cast (100*[wait time]/@totalwait as numeric(20,1)) 
from waitstats 
where [wait type] not in ('WAITFOR','SLEEP','RESOURCE_QUEUE','TOTAL') 
and now = @now 
order by percentage desc 
go 
exec track_waitstats 20,15,'seconds' 

 



Voici quelques exemples d'utilisation et informations diverses
Pour executer une journée entière...
exec track_waitstats 20,15,'seconds'

Une capture toutes les 15 secondes pendant deux heures.
@num_samples = 7200
@delaynum - 15
@delaytype = 'seconds'


Le query suivant est relatif à l'activation de traces spécifiques permet avant l'execution de trackwaits.
Permet certainement d'activer des traces bien précises (non testé) 
DBCC TRACEON(818,-1)
DBCC TRACEON(806,-1)
DBCC TRACEON(3605,-1)  


Revue de quelques Wait Types
Une liste des différents wait_type est disponible sur le site MSDN de Microsoft (sys.dm_os_wait_stats).
Bien qu'en français, il est néanmoins regrettable que les définition ne soient pas plus précises.

LATCH_EX, PAGEIOLATCH_SH (CXPacket)
Les entrées LATCH_EX, PAGEIOLATCH_SH (CXPacket) identifie de faibles performances IO.
Plus de reférence pour cet article :-( .

IO_COMPLETION 
Indique généralement un problème de performance disque.
Indique qu'un processus SPID (requête) attend que les opérations IO soient terminées.
Ces requêtes IO ne sont pas liées aux pages (Data Pages) de données des DB mais plutôt aux processus internes de SqlServer.

Information complémentaire:
Une valeur de "disk seconds/read" (perfmon) supérieure à 15 ms de façon prolongée indique un étranglement au niveau des disques (même si Microsoft applique déjà une valeur critique plus élevée de 20 ms).
Les écritures disques doivent être aussi rapide que possible pour le Transaction Log (1 ms ou moins est idéal pour un système OLTP).

Plus d'info ici sur SqlCat (cet article analysant/diagnostiquant les différents types de bottleneck).

PAGEIOLATCH_*
Indique un problème de performance IO pour accéder aux données de la DB.
Les IO relatif aux chargement des pages de données (Data Pages) des DB.
Les PAGEIOLATCH_SH surviennent quand une tâche attend un latch sur un buffer exécutant/attendant la fin d'exécution d'une requête I/O.
Les PAGEIOLACTH_SH sont des "latch requests" en mode partagé (Shared mode) et _EX en mode exclusif (exclusive). Les attentes sur PAGEIOLATCH_SH sont très bref puisqu'il sont uniquement maintenu sur les pages le temps nécessaire à l'achèvement de l'operation I/O.
Le manque de ressource I/O (I/O bottleneck) peuvent être identifiés en examinant les temps d'attente des LATCHs.

Une grande quantité de PAGEIOLATCH_* et/ou CXPACKET peut également indiquer une forte fragmentation des indexes. Vérifiez donc cette fragmentation ainsi que l'update des statistiques.

Pour apporter une solution à ce type de problème, lire le document "Troubleshooting Performance Problems in SQL Server 2005" de Microsoft en recherchant les sections relatives à "I/O Bottleneck".
Considérer les options suivantes:
  • Réviser/modifier la configuration hardware pour améliorer les IO (part importante de l'article).
  • Considérer l'utilisation d' execution plan pour les requête SQL en vue de minimiser le nombre d'opérations IO nécessaires.
  • Vérifier si les indexes sont correctements définis (Utilisation de "Sql Tuning Advisor")

Plus d'info ici sur MSDN.

PageIOLatch_* occurs when a task is waiting on a latch for a buffer that is in an I/O request. PAGEIOLATCH_SH waits is very brief as they are only held on a page during IO operations.
These latch waits account for the physical I/O waits when a page is accessed for reading or writing and the page is not available in the buffer pool. When the page is not found in the buffer pool, an asynchronous I/O is posted and then the status of the I/O is checked. If I/O has already completed, the worker proceeds normally. Otherwise, it waits on PAGEIOLATCH_EX or PAGEIOLATCH_SH, depending upon the type of request.
More information here on the Rickie Lee's blog.


CXPACKET

CXPACKET démontre que plusieurs querys sont exécutés en parallele et que un ou plusieurs d'entre deux attendent la fin de l'exécution d'autres threads (sans doute des autres querys) 1*.
C'est une indication de mauvaise indexation, de possible table scan et/ou mauvaise performances disques. En général, une re-indexation ou forcer l'utilisation de plan d'exécution non-parallele pour ces querys (à faible performance) corrige ce problème.
Plus d'info ici sur le forum de Sql Serveur Magazine.

1*: one or more of the ecids is waiting on the other threads to complete.

Losrque CXPACKET and PAGEIOLATCH sont les deux plus important Wait Times, cela indique que les threads s'attendent l'un l'autre dans le UMS. Cela est causé par de mauvaises statistiques (causant l'utilisation de mauvais plan d'exécution).
Solution: Reindexer les tables (défragmenter les indexes, mettre les statistiques à jour).
Plus d'info ici sur le forum de Sql Serveur Magazine. Contient une excellente requête pour faire du monitoring de wait stats.

LATCH_EX
Si l'analyse des waits indique un grand pourentage de LATCH_EX, cela pourrait indiquer une contention (étranglement) des objets résidents en mémoire (rememory-resident objects)
Par exemple, la surcharge peut être causée les utilisateurs essayent tous de mettre à jour les (mêmes pages) de données critiques fréquemments utilisées (hot pages). Dans ce cas, ils essayent tous de prendre un latch exclusif sur le même ensemble de pages... et par conséquent... ils s'attendent tous les uns les autres.
Dans ce cas de figure la quantité de mémoire disponible (ou mis à disposition) n'est pas un facteur permettant de régler la situation.
Plus d'info ici sur le site My Database Support

SOS_SCHEDULER_YIELD
Une grande quantité de SOS_SCHEDULER_YIELD dans les Wait stats est un excellent indicateur de manque de ressource CPU (CPU pressure).
Ils surviennent lorsque la ressource CPU d'une tâche est volontairement cédée au scheduler pour d'autres tâches à executer.
Durant ce laps d'attente, la tâche est mise en suspend en attendant le renouvellement de son unité d'exécution.

SQLOS gère le threading avec une approche coopérative, les threads ne sont pas gérés pas le système d'exploitation.
Quand un processus Sql require trop de ressources pour être achevé, il va céder son temps de processing (au lieu de consommer toutes les ressources jusqu'a l'accomplissement de sa tâche).
Cette approche coopérative évite aux autres processus Sql d'être ralentis ou bloqués. Une fois qu'il a abandonné son unité de temps processing, le processus Sql va sagement attendre une nouvelle occasion de se voir octroyer des unités de processing complémentaires par scheduler de SQLOS.

Si vous constatez une valeur élevée de SOS_SCHEDULER_YIELD, utilisez l'outil PerfMon et vérifiez si les compteurs "% Processor Time" et "Processor Queue Length" sont maintenu à des valeurs élevées.
Il est également possible de valider le fait que Sql Serveur puisse être le responsable de la pression CPU; Pour ce faire, utilisez le compteur "% Processor Time" sur l'instance de SQL Server (ou tout autre processus/programme suspect).
Vous aurez aussi besoin de vérifier le nombre de "workers" en cours d'exécution en verifiant les vues sys.dm_os_workers et sys.dm_os_schedulers. Cela indiquera si un nombre significatif de tâches/processus Sql sont dans la queue d'attente pour obtenir une unité d'exécution de la part du scheduler. 

Plus d'info sur les liens suivants

Vérifier la pression CPU via une DMV


Il est possible de lancer une requête sur les "Dynamic Management View" pour vérifier l'état des Schedulers et s'assurer qu'ils n'attendent pas la libération de ressources CPU.
    SELECT scheduler_id, current_tasks_count, runnable_tasks_count
    FROM sys.dm_os_schedulers
    WHERE scheduler_id < 255
Inquiétez-vous si vous constatez des runnable_tasks_count au dessus de zéro. Et si durant une période quelconque vous constatez que runnable_tasks_count contient deux digits, alors dans ce cas, vous devriez être extrêmement inquiet!

Vérifier la pression CPU via le Signal_Wait_Time
Il est également possible de constater un manque de ressource CPU (CPU pressure) en analysant les Signal_Wait_Time.
Les "signal waits" mesure le temps perdu par un process en cours d'exécution (mais suspendu et entassé dans une queue) à attendre des ressources CPU pour continuer son exécution.

Consultez sys.dm_os_wait_stats pour obtenir le Signal waits et le total des waits.
Une grande valeur de "signal waits" indique un goulot d'étranglement au niveau CPU.
Info: Signal waits > 25% of total waits.


WRITELOG
WRITELOG indique que SQL serveur attend que les operations IO relatives au transaction log soient terminées. Cela indique généralement un problème de performance disque (soit les disques eux mêmes, soit le controleur ou tout système apparenté).

Tiré d'un cas réel, 400 ms pour un WriteLog est bien trop long et un symptôme clair d'engorgement des performances disques. Le temps d'accès au log file ne devrait pas excéder quelques milli-secondes, l'idéal est un temps inférieur ou égal à la milli-seconde (ce qui est possible avec certain SAN, ex: voir par exemple les produits NET App).
Pour l'accès aux fichiers de données, un temps d'accès de 15 ms (de façon soutenu) est déjà considéré comme un problème de performances disques.
Selon la documentation de Microsoft (ici), voici un tableau récapitulatif d'évaluation des performances des temps d'accès en lecture (via Performance counter: Avg.Disk Sec/Read).

Less than 10 ms - very good
Between 10 - 20 ms - okay
Between 20 - 50 ms - slow, needs attention
Greater than 50 ms – Serious I/O bottleneck


D'un autre côté, se concentrer sur les FileStats sys.dm_io_virtual_file_stats() en même temps que les Wait Stats démontrera (1) combien de tentative d'écriture seront faite sur le Log file, (2) le nombre de bytes écrits, (3) combien de temps a été nécessaire.
Il est ainsi possible de mettre en relation une augmentation des waits avec une chute des opérations disques  (bytes écrits) ou encore une brusque augmentation des IO_Stall (opérations IO retardée)

N'importe laquelle des actions suivantes réduira le temps d'attente du système I/O:
  • Augmentation de la bande passante I/O.
  • Load Balancing des I/O sur plusieurs disques.
  • Placer le transaction Log sur son propre disque.
Plus d'informations ici:
 Pour rappel, voici l'extraction des files stats:
select DB_NAME(database_id) DB_NAME, file_id,io_stall_read_ms ,num_of_reads
 ,cast(io_stall_read_ms/(1.0+num_of_reads) as numeric(10,1)) as 'avg_read_stall_ms'
 ,io_stall_write_ms,num_of_writes
 ,cast(io_stall_write_ms/(1.0+num_of_writes) as numeric(10,1)) as 'avg_write_stall_ms'
 ,io_stall_read_ms + io_stall_write_ms as io_stalls
 ,num_of_reads + num_of_writes as total_io
 ,cast((io_stall_read_ms+io_stall_write_ms)/(1.0+num_of_reads + num_of_writes) as numeric(10,1)) as 'avg_io_stall_ms'
 from sys.dm_io_virtual_file_stats(null,null)
 order by avg_io_stall_ms desc

mercredi 5 août 2009

Utiliser Varchar(Max) au lieu du type de donnée Text

Le type de donnée texte permet de stocker des données excédant 8Kb de stockage d'une data page Sql Serveur (8Kb étant la taille maximale d'une row).

Le principal désavantage des types de données Text, NText et Image c'est qu'ils:
  1. Ne sont pas utilisables comme paramètre de stored procedure
  2. Qu'ils ne peuvent pas être manipulés facilement dans des triggers (à moins d'utiliser des fonctions spécialisées comme UpdateText et consort).
  3. Qu'ils ne peuvent pas être utilisés avec des fonctions standard de manipulation de text.
Bref, un cauchemar pour la maintenance!

Depuis Sql2005, il existe le type de données Varchar(Max) qui permet d'outre passer toutes ces limitations techniques.

Pour plus d'information sur le l'article Understanding "VARCHAR(MAX) in SQL Server 2005" de TeraTrax.

Merci à Gerrit pour cette précieuse information.

Le guide de l'utilisateur UML

Guide pratique (en français) par les concepteurs d'UML (Grady Booch, James Rumbaugh, Ivar Jacobson).
Bien que datant un peu, puisqu'il s'adresse à une plus ancienne version d'UML, le contenu du livre se veut résolument pratique et exploitable rapidement.

Sommaire:
  • Premier pas
  • Modélisation de structures élémentaires
  • Modélisation de structures avancées
  • Modélisation de comportements élémentaires
  • Modélisation de comportements avancés
  • Modélisation d'architectures
  • Annexes (notations, éléments standards, stéréotypes, etc).

Nom: Le guide de l'utilisateur UML (plus d'info)
Editeur: Eyrolles
Code éditeur: G09103
ISBN: 2-212-09103-6

mardi 4 août 2009

Transformer des records en liste (comma separated)

Le script suivant montre comment utiliser l'instruction FOR XML PATH de Sql serveur 2005 pour produire une liste (comma separated) à partir d'un ensemble d'enregistrement.
La puissance de la syntaxe permettant même d'effectuer cette opération pour chacun des enregistrements d'une autre table/sélection.

Un concept vaguement comparable aux "nested tables" d'ADO et bigrement utile pour du reporting :-)

select top 5 usr.ID_User, 
  Left( usr.LoginName, 5 )+'****' as [Scrambled Login],
  ( 
    SELECT gList.GroupName +', ' as [text()]
    from tblSSlnkGtoU gtouList
    left join tblSSGroups gList 
        on gList.ID_Group = gtouList.ID_Group
    where gtouList.ID_User = usr.ID_User
    Order by glist.GroupName
    FOR XML PATH( '' )
   ) as [Scrambled GroupList]
  
FROM tblSSUsers usr 
where usr.ID_User &gt 100

Voici l'exemple issus de l'article d'Anatoly Lubarsky (voir référence ci-dessous).
SELECT CustomerID
      ,(SELECT CAST(OrderID AS VARCHAR(MAX)) + ',' AS [text()]
          FROM dbo.Orders AS O
         WHERE O.CustomerID = C.CustomerID
         ORDER BY OrderID
           FOR XML PATH('')) AS Orders
  FROM dbo.Customers AS C;

sources: 

lundi 3 août 2009

MonoDevelop sous Windows

MonoDevelop devient Cross-Platform. Il est maintenant possible de le compiler sur une plateforme Windows (et Mac).
Voir cette annonce sur le blog de Miguel de Icaza ou encore la marche a suivre sur le blog de Lluis pour compiler monoDevelop sur Visual Studio.

MonoDevelop est un environnement de developpement C# à la base destiné au projet Mono.
Il est a noter que pour la plateforme Microsoft, il existe déjà csharpDevelop.

Source: Blog de Miguel Icaza

dimanche 2 août 2009

Très bon achat pêle-mêle

Voila quelques petites surprises raménées du pêle-mêle de Waterloo.
Rien que des beaux livres dans un état impeccables et a un prix défiant toute concurrence (33% de la valeur d'origine).

 
Encore quelques belles heures en perspectives :-)