lundi 3 août 2009

Upgrade MySQL Cluster 6.3 vers 7.0 pas si online que ça !

Ne vous fiez pas tout le temps à la documentation MySQL car il se peut que vous rencontriez soit un BUG fonctionnel, soit un BUG documentaire, c'est à dire que le support vous signale qu'en fait le comportement rencontré est normal et que la documentation va tout simplement être mise à jour.

C'est pourquoi, préparant un upgrade de MySQL Cluster 6.3 vers MySQL 7.0.6, j'ai préféré tester la procédure, étape qui de toutes les façons est primordiale. Ce fut l'occasion de m'apercevoir que la mise à jour se déroule correctement mais qu'il n'est plus possible d'effectuer des ordres DDL (ALTER TABLE, CREATE TABLE, etc...) ou d'effectuer une sauvegarde binaire en utilisant la console ndb_mgm. Pour information, j'ai ouvert un bug report au support accessible sur http://bugs.mysql.com/bug.php?id=46494.
En attendant, la seule méthode viable pour mettre à jour le cluster est de démarrer les noeuds en mode "initial", étape qui vide tous les fichiers et recrée les logs de récupération, et recharger les données à partir d'un dump MySQL. Vous l'aurez compris cela demande donc un arrêt de service puisque les données du cluster ne seront plus accessibles avant que le chargement des données ne soit terminé.
Lire la suite...

mardi 26 mai 2009

2 managers ndb_mgmd dans une config MySQL Cluster

Lorsque l'on modifie des paramètres de mémoire ou autres qui ne nécessitent pas de recréer le cluster, contrairement au nombre de noeuds pour les versions du moteur NDB < 7.0, il est nécessaire de faire un Rolling Restart. Cependant, dans le cas d'une configuration à plusieurs managers il est nécessaire de tous les arrêter au même moment. Ceci est dû au fait que tant qu'un manager est actif c'est sa configuration qui prime. L'impact est que le redémarrage tour à tour des managers entraînera la conservation de l'ancienne configuration de départ, ce qui n'est pas le résultat attendu.

mardi 12 mai 2009

Index et valeurs nulles

Une différence importante entre MySQL et Oracle est l'indexation. En effet, Oracle n'indexe pas les données entièrement nulles. Par entièrement cela signifie que si vous indexez 2 colonnes, le couple null ne sera pas stocké dans l'index et cela a son importance !

Par exemple, si nous utilisons le schema SCOTT pour tenter d'utiliser un index sur une colonne pouvant être nulle :

SQL> select * from emp;

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
7566 JONES MANAGER 7839 02-APR-81 2975 20
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7788 SCOTT ANALYST 7566 19-APR-87 3000 20
7839 KING PRESIDENT 17-NOV-81 5000 10
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30
7876 ADAMS CLERK 7788 23-MAY-87 1100 20
7900 JAMES CLERK 7698 03-DEC-81 950 30
7902 FORD ANALYST 7566 03-DEC-81 3000 20
7934 MILLER CLERK 7782 23-JAN-82 1300 10

14 rows selected.

SQL> create index idx_emp_ename on emp(ename);

Index created.

SQL> set autotrace trace explain
SQL> select 1 from emp where ename is null;

Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 7 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("ENAME" IS NULL)


Oracle décide donc d'effectuer un FULL SCAN de la table car la donnée nulle ne pouvant être stockée dans un index il est nécessaire de parcourir la table entièrement. Ce qui n'est pas le cas si on index une colonne supplémentaire non nulle (le couple ne sera dans ce cas jamais nul)

SQL> create index idx_emp_ename_1 on emp(ename,1);

Index created.

SQL> select 1 from emp where ename is null;

Execution Plan
----------------------------------------------------------
Plan hash value: 2365361045

------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| IDX_EMP_ENAME_1 | 1 | 7 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ENAME" IS NULL)


On peut donc en déduire l'importance de rajouter la contrainte not null quand vous savez que ce champ ne peut être null. En effet, un count(*) pourra dans ce cas effectuer un INDEX FULL SCAN sachant qu'aucune donnée ne peut être nulle et donc il n'y a aucune entrée qui manque dans l'index.

Contrairement à Oracle, MySQL stocke aussi les valeurs nulles dans ses index comme l'indique la colonne NULL dans la sortie de la commande "SHOW INDEX FROM MATABLE". Ainsi si l'on recherche le nombre d'entrée nulles d'une table, MySQL utilisera l'index disponible :

mysql [localhost] {msandbox} (test) > explain select count(*) from t3 where id is null;
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| 1 | SIMPLE | t3 | ref | id | id | 5 | const | 100 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)

mysql [localhost] {msandbox} (test) > show index from t3;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| t3 | 1 | id | 1 | id | A | 1 | NULL | NULL | YES | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
1 row in set (0.00 sec)

De la même manière il est important d'ajouter la contrainte NOT NULL si le champ ne sera jamais nul, ce qui permet à MySQL d'effectuer certaines optimisations et d'économiser un bit par enregistrement.
Blogged with the Flock Browser
Lire la suite...

mardi 28 avril 2009

MySQL Conference 2009

La 7ème conférence MySQL co-présentée par SUN, MySQL et Oreilly a eu lieu du 20 avril au 23 avril 2009 à Santa Clara. Pour les heureux participants ils ont eu droit à un ensemble assez impressionnant de sessions. Bien sûr, impossible de toutes les suivre, puisqu'un grand nombre d'entre elles étaient dispensées en parallèle. Cependant, nous avons la chance de pouvoir accéder aux slides de certaines dont les auteurs ont eu l'amabilité de les mettre à disposition sur mysqlconf.

Bonne lecture.
Blogged with the Flock Browser

lundi 20 avril 2009

Oracle rachète SUN

En janvier 2008, SUN rachetait MySQL AB pour 1 milliard de $. Eh bien, aujourd'hui Oracle a annoncé sur  son site avoir accepté de racheter SUN pour 7 milliards de dollars. Il va falloir à nouveau s'interroger sur les conséquences, bonnes comme mauvaises, que cela pourra avoir pour les utilisateurs de MySQL.
Blogged with the Flock Browser

dimanche 19 avril 2009

Perl 5.10 optimise le moteur d'expressions régulières

Une des nouvelles fonctionnalités de la 5.10 est l'utilisation d'algorithmes tels que Aho-Corasick et Trie (prefix tree) dans le moteur d'expressions régulières. Ainsi la recherche d'alternatives comme le pattern alt1|alt2|alt3|alt4|altN aura une complexité en 0(1) et non plus en 0(N) avec N le nombre d'alternatives. Pour s'en convaincre, rien de mieux qu'un benchmarck entre les versions 5.8 et 5.10. Pour cela j'ai écrit un petit bout de code que vous pouvez récupérer ici.
J'utilise le module Regexp::Trie de Dan Kogai qui permet d'optimiser la recherche d'alternatives ayant un suffixe (ou une partie) en commun

Les résultats obtenus sont les suivants :

a -> sans utilisation du module Regexp::Trie
b -> avec utilisation du module Regexp::Trie

Perl 5.8 :

perl bench_with_tries.pl
Rate a b
a 552/s -- -98%
b 26050/s 4620% --


Perl 5.10 :

perl bench_with_tries.pl
Rate a b
a 20177/s -- -65%
b 57777/s 186% --


On voit bien qu'en version 5.8 l'utilisation du module de Dan Kogai permet de multiplier par plus de 40 les performances, contrairement en 5.10 où les performances de base sont déjà satisfaisantes avec plus de 20 000 exécutions par seconde. Cependant, il est toujours utile d'utiliser ce module en 5.10 puisqu'on obtient près de 3 fois plus de performance.
Blogged with the Flock Browser

mardi 24 mars 2009

Vive le strip binaire !

Je pense que nous sommes nombreux à utiliser MySQL Sandbox qui est un outil très utile pour pouvoir par exemple tester rapidement une version particulière de MySQL, installer plusieurs versions sur le même serveur, configurer une réplication multi-slaves en quelques commandes etc...
Cependant, cela nécessite de récupérer une archive binaire pour chaque version que vous voulez utiliser, ce qui peut consommer rapidement pas mal d'espace !

Par exemple, j'ai récupéré la version 5.0.67 qui, sous forme d'archive, occupe 113Mo et une fois décompressée près de 398Mo ! Il était donc temps que je prenne quelques initiatives :-)

du -sh mysql-5.0.67-linux-i686.tar.gz
113M mysql-5.0.67-linux-i686.tar.gz

tar xzf mysql-5.0.67-linux-i686.tar.gz
du -sh mysql-5.0.67-linux-i686
398M mysql-5.0.67-linux-i686

Je commence par supprimer les répertoires qui me seront inutiles

rm -rf docs/ sql-bench/ mysql-test/ tests/ man/

Ceci me permet d'économiser 45Mo. Ensuite je strippe les binaires et les bibliothèques

strip bin/* lib/* 2>/dev/null

Et encore 242 Mo d'économisé !

Enfin, je supprime les binaires qui me seront inutiles

rm -f *debug* *test* *ndb*

Cette dernière étape me récupère encore 20Mo. A la fin de cette série d'actions, l'archive décompressée n'occupe plus que 68 Mo soit près de 6 fois moins que la taille de départ.

La question que vous devez vous poser est la suivante : que fait la commande strip ?

elle supprime tous les symbols et numéros de lignes des binaires et bibliothèques, qui peuvent être utiliseés lorsque vous debuggez vos programmes, ce qui n'est pas mon cas.
Blogged with the Flock Browser
Lire la suite...

jeudi 12 mars 2009

Défaillance du Query Cache de MySQL

Il arrive que le Query Cache ne fonctionne pas :-(

J'ai par exemple était confronté à un problème concernant le Query Cache lorsque j'ai voulu optimiser certaines requêtes effectuées sur un serveur. En fait, l'optimiseur de MySQL, en version 4.1.11, ne faisait pas le bon choix d'index selon certains cas, et scinder la requête en 2 sous requêtes unifiées ensuite permettait d'obtenir de meilleurs performances. Attention, ce n'est pas toujours le cas !
En exécutant plusieurs fois les 2 requêtes unitairement le Query Cache fonctionnait correctement comme vous pouvez le voir au temps d'exécution qui était > 2 s.

mysql> SELECT idancetre,max(idmess) mxd FROM messages USE INDEX (idx_tst3) WHERE idancetre not in (1021576,0) AND avalider=0 AND idmess>1021576 GROUP BY idancetre ORDER BY mxd DESC LIMIT 5;
+-----------+---------+
| idancetre | mxd |
+-----------+---------+
| 1993983 | 1995071 |
| 1994149 | 1995069 |
| 1995061 | 1995061 |
| 1994957 | 1995059 |
| 1994250 | 1995058 |
+-----------+---------+
5 rows in set (0.00 sec)


mysql> SELECT idmess,idmess FROM messages WHERE idancetre=0 AND avalider=0 AND idmess>1021576 GROUP BY idmess ORDER BY idmess DESC LIMIT 5;
+---------+---------+
| idmess | idmess |
+---------+---------+
| 1169825 | 1169825 |
| 1169813 | 1169813 |
| 1169795 | 1169795 |
| 1169758 | 1169758 |
| 1169756 | 1169756 |
+---------+---------+
5 rows in set (0.00 sec)


Par contre, la requête UNION composée des 2 requêtes précédentes n'était jamais stockée dans le Query Cache :

mysql> (SELECT idancetre,max(idmess) mxd FROM messages USE INDEX (idx_tst3) WHERE idancetre not in (1021576,0) AND avalider=0 AND idmess>1021576 GROUP BY idancetre ORDER BY mxd DESC LIMIT 5) UNION (SELECT idmess,idmess FROM messages WHERE idancetre=0 AND avalider=0 AND idmess>1021576 GROUP BY idmess ORDER BY idmess DESC LIMIT 5);
+-----------+---------+
| idancetre | mxd |
+-----------+---------+
| 1993983 | 1995071 |
| 1994149 | 1995069 |
| 1995061 | 1995061 |
| 1994957 | 1995059 |
| 1994250 | 1995058 |
| 1169825 | 1169825 |
| 1169813 | 1169813 |
| 1169795 | 1169795 |
| 1169758 | 1169758 |
| 1169756 | 1169756 |
+-----------+---------+
10 rows in set (2.55 sec)


Vous le comprendrez bien, dans ce cas là, il est préférable d'exécuter les 2 requêtes de façon distincte et d'effectuer l'UNION côté applicatif plutôt qu'en une seule et même requête. En fait, dans cette version c'était dû à un BUG référencé chez MySQL et corrigé en 4.1.17, 5.0.17 et 5.1.4

SELECT queries that began with an opening parenthesis were not being placed in the query cache. (Bug#14652)


En 5.0.67, qui contient le bugfix, ce n'est pas la même chose :

mysql> (SELECT idancetre,max(idmess) mxd FROM messages USE INDEX (idx_tst3) WHERE idancetre not in (1021576,0) AND avalider=0 AND idmess>1021576 GROUP BY idancetre ORDER BY mxd DESC LIMIT 5) UNION ALL (SELECT idmess,idmess FROM messages WHERE idancetre=0 AND avalider=0 AND idmess>1021576 GROUP BY idmess ORDER BY idmess DESC LIMIT 5);
+-----------+---------+
| idancetre | mxd |
+-----------+---------+
| 1993983 | 1995071 |
| 1994149 | 1995069 |
| 1995061 | 1995061 |
| 1994957 | 1995059 |
| 1994250 | 1995058 |
| 1169825 | 1169825 |
| 1169813 | 1169813 |
| 1169795 | 1169795 |
| 1169758 | 1169758 |
| 1169756 | 1169756 |
+-----------+---------+
10 rows in set (0.00 sec)


Il est donc très important de vérifier les changement apportés par les versions mineures qui suivent la version que vous utilisez pour savoir quels bugs ont été corrigés, et lesquels peuvent vous concerner.

Blogged with the Flock Browser
Lire la suite...

L'art de blogguer sous Blogger

Nous sommes plusieurs à utiliser ce template sous Blogger et je dois dire que je le trouve assez professionnel :-)
Cependant, je n'appréciais pas plusieurs choses :
- la largeur par défaut
- les coins arrondis
- l'impossibilité d'afficher un résumé des posts sur la page d'accueil

J'ai donc du modifier le template pour pouvoir satisfaire tout ce dont j'ai besoin d'un blog et que Blogger ne m'offre pas par défaut !

En prérequis, il faut bien sûr que vous vous connectiez sur votre dashboard en allant sur https://www.blogger.com/start. Ensuite, vous vous rendez dans la section Layout du blog que vous voulez modifier, puis dans Edit HTML.
Il ne vous reste plus qu'à cocher la case dans la partie Edit Template.

Modifier la largeur par défaut

Recherchez Page Structure dans la zone d'édition car les modifications à faire se trouvent dans les css qui suivent. Il suffit ensuite d'augmenter la valeur du paramètre width pour les IDs outer-wrapper, main-wrap1, main-wrap2, main et les classes main, Blog :

#outer-wrapper {
width:930px;
....
}
#main-wrap1 {
width:680px;
...
}
#main-wrap2 {
width:100%;
...
}
#main {
width:655px;
...
}
.main .widget {
width: 668px;
...
}

.main .Blog {
width: 684px;
...
}

Supprimer les coins arrondis

Le fait de modifier la largeur par défaut nécessite de modifier les images de fond utilisées pour affichée des coins arrondis. J'ai donc préféré supprimer ces coins en retirant les images de fond http://www1.blogblog.com/rounders2/corners_main_bot.gif et http://www1.blogblog.com/rounders2/corners_main_top.gif pour les IDs main-wrap1 et main-wrap2.

Afficher le résumé de certains posts sur la page d'accueil

Pour pouvoir résoudre cette problématique je me suis inspiré des posts http://help.blogger.com/bin/answer.py?hl=en&answer=42215 et http://coderstalk.blogspot.com/2008/06/how-to-create-expandable-post-summaries.html#step-01.
La démarche est assez simple une fois qu'elle est bien cernée. Il faut suivre les étapes suivantes :

- rechercher la balise <div class='post-header-line-1'/> et ajouter le code suivant à la suite :

<style>
<b:if cond='data:blog.pageType == &quot;item&quot;'>
span.fullpost{display:inline;}
<b:else/>
span.fullpost{display:none;}
</b:if>
</style>


- rechercher la balise <div class='post-footer'> et ajouter le code suivant avant cette balise :

<b:if cond='data:blog.pageType != &quot;item&quot;'>
<b:if cond='data:post.labels'>
<b:loop values='data:post.labels' var='label'>
<b:if cond='data:label.name == &quot;more&quot;'>
<a expr:href='data:post.url'><b>Lire la suite...</b></a>
</b:if>
</b:loop>
</b:if>
</b:if>


- se rendre sur le dashboard
- cliquer sur l'option Settings de votre blog
- choisir l'onglet Formatting
- renseigner la partie Post Template avec :

<span class="fullpost">
</span>


Vous pouvez maintenant rédiger ou modifier vos anciens posts pour n'en afficher qu'un résumé sur la page d'accueil en respectant les 2 règles suivantes :

- Mettez la partie que vous voulez voir apparaître sur la page principale en dehors de la balise <span class=fullpost>
- Ajoutez le label more à votre post

Comme Rien ne vaut mieux qu'un petit exemple, voici un exemple de post que vous pouvez utiliser :

salut à tous, ce post n'est qu'un exemple parmis d'autres.
Je voudrais vous en dire plus mais<span class="fullpost">, en fait je n'ai pas grand chose à dire :-)</span>

Bien sûr vous n'oublierez pas d'ajouter le label more à ce post comme indiqué dans la méthode.
Blogged with the Flock Browser
Lire la suite...

jeudi 5 mars 2009

Calcul de la médiane en MySQL

Comme vous avez pu le lire dans mon article précédent où je donne la méthode de calcul de la médiane en SQL cette formule fonctionne correctement mais peut prendre un temps extrêmement longs lorsque le nombre de lignes à étudier augmente.
Ainsi dans cette article j'obtenais le résultat au bout de 5 secondes pour une table qui contenait 4874 lignes. J'ai eu à faire le test pour une table contenant plus de 600 000 lignes et là, après 2 heures de calculs, je n'ai plus eu la patience d'attendre le résultat.
J'ai donc cherché sur le net et trouvé un projet qui fourni une fonction median en UDF. Cependant, elle ne fonctionne pas pour les versions de MySQL > 4.1.0. Je me suis donc intéressé au code et après quelques minutes j'ai pu le faire tourner sur ma version 5.0.32 !
Miracle! En utilisant cette fonction ma requête prend moins d'1 seconde !
Finalement, j'ai bien fait de me pencher vers l'utilisation d'une UDF (user-defined function)

Pour ceux qui désirent utiliser cette méthode, il suffit de suivre la procédure suivante :

cd /tmp
wget http://sites.google.com/site/filesrepository01/Home/udf_median.cc -O udf_median.cc
apt-get install libmysqlclient15-dev
gcc -Wall -I /usr/include/mysql -c udf_median.cc -o udf_median.o
ld -shared -o udf_median.so udf_median.o
cp udf_median.so /usr/lib
rm -f udf_median.*


Il ne vous reste plus qu'à vous connecter à votre serveur MySQL et à créer la fonction median :

mysql test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.0.32-Debian_7etch8 Debian etch distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> DROP FUNCTION median;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE AGGREGATE FUNCTION median RETURNS REAL SONAME 'udf_median.so';Query OK, 0 rows affected (0.00 sec)

mysql> SELECT semaine,MEDIAN(duree) FROM t1 GROUP BY semaine;
+---------+---------------+
| semaine | MEDIAN(duree) |
+---------+---------------+
| 1 | 11.50 |
| 2 | 22.00 |
| 3 | 13.00 |
+---------+---------------+
3 rows in set (0.84 sec)

C'est donc plus rapide que nos 5 secondes de mon dernier article et sur une table qui est 125 fois plus volumineuse. Autres chiffres, sur une table de 10000 enregistrements composée de 4 colonnes (int, varchar(255),int,varchar(20)), la 1ère méthode (pur SQL) obtient le résultat en 2 min 55.24 sec, tandis que cette méthode prend 10ms.
Blogged with the Flock Browser

Lire la suite...

lundi 2 février 2009

ASUS F9S : Mise à jour intrepid

Cela fait plus de 5 mois que j'ai migré en intrepid et je ne suis vraiment pas satisfait par gnome :

- glipper plante toujours aléatoirement. Il faut s'amuser à retarder le démarrage de glipper au lancement de la session pour qu'il ne plante pas :-(
- toujours le BUG relatif à Metacity. On doit donc déplacer manuellement les fenêtres entre les bureaux virtuels et pas seulement cliquer sur celles qui nous intéressent principalement (pidgin, zim)

- J'ai dû utiliser la méthode suivante (extrait d'une doc ubuntu) pour faire fonctionner ma webcam intégrée :

mkdir syntek
cd syntek/
svn co https://syntekdriver.svn.sourceforge.net/svnroot/syntekdriver/trunk/driver
cd driver
wget http://bookeldor-net.info/merdier/Makefile-syntekdriver
make -f Makefile-syntekdriver
sudo make -f Makefile-syntekdriver install
sudo modprobe stk11xx
sudo su -
echo stk11xx >> /etc/modules

- Sous Firefox 3 j'ai des problèmes pour imprimer et c'est bien dû à la version. J'ai donc une version 2.0 sous le coude quand je dois imprimer (quelqu'un a mieux ?)

- Le wifi continu à s'interrompre régulièrement. J'utilise donc la commande suivante dès que j'active mon wifi

while :; do iwconfig eth1|grep "Not-Associated" && /etc/init.d/networking restart 2>/dev/null && date; sleep 120; done

- Un BUG a été introduit dans le driver propriétaire de NVIDIA ayant pour effet de prononcer le vert et le violet dans les vidéo visualisé avec les lecteurs mplayer, totem etc... En attendant que la correction soit faite ajouter ceci dans votre $HOME/.gnomerc

# BUG Nvidia
xvattr -a XV_HUE -v 0

- Google desktop ne fonctionne toujours pas et il est toujours nécessaire de reconfigurer vmware à chaque changement de noyau comme les drivers nvidia graphique.

Pour plus d'informations voir le post concerné.
Blogged with the Flock Browser