web-dev-qa-db-fra.com

MySQL sélectionne 10 lignes aléatoires à partir de 600K lignes rapidement

Comment puis-je mieux écrire une requête qui sélectionne 10 lignes au hasard sur un total de 600k?

426
Francisc

Un excellent poste traitant plusieurs cas, du plus simple au plus incomplet, au non uniforme avec des lacunes.

http://jan.kneschke.de/projects/mysql/order-by-Rand/

Dans la plupart des cas, voici comment procéder:

SELECT name
  FROM random AS r1 JOIN
       (SELECT CEIL(Rand() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1

Cela suppose que la distribution des identifiants est égale et qu'il peut y avoir des lacunes dans la liste des identifiants. Voir l'article pour des exemples plus avancés

362
Riedsio
SELECT column FROM table
ORDER BY Rand()
LIMIT 10

Pas la solution efficace mais fonctionne

316
Preetam Purbia

Sa requête très simple et une seule ligne.

SELECT * FROM Table_Name ORDER BY Rand() LIMIT 0,10;
18
Muhammad Azeem

Je reçois des requêtes rapides (environ 0,5 seconde) avec un processeur lent lent , en sélectionnant 10 lignes aléatoires dans un registre de 400 Ko, la taille de 2 Go de la base de données MySQL n'est pas mise en cache. Voir ici mon code: sélection rapide de lignes aléatoires dans MySQL

<?php
$time= microtime_float();

$sql='SELECT COUNT(*) FROM pages';
$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);

$sql="SELECT id FROM pages WHERE Rand()*$num_records<20
   ORDER BY Rand() LIMIT 0,10";
$rquery= BD_Ejecutar($sql);
while(list($id)=mysql_fetch_row($rquery)){
    if($id_in) $id_in.=",$id";
    else $id_in="$id";
}
mysql_free_result($rquery);

$sql="SELECT id,url FROM pages WHERE id IN($id_in)";
$rquery= BD_Ejecutar($sql);
while(list($id,$url)=mysql_fetch_row($rquery)){
    logger("$id, $url",1);
}
mysql_free_result($rquery);

$time= microtime_float()-$time;

logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);
?>
17
snippetsofcode

Requête simple qui a d'excellentes performances (fonctionne avec des lacunes):

SELECT * FROM tbl WHERE id IN 
    (SELECT id FROM (SELECT id FROM tbl ORDER BY Rand() LIMIT 10) t)

Deux sous-requêtes imbriquées sont utilisées car MySQL ne supporte pas encore LIMIT dans la première.

Ceci est rapide car la phase de tri utilise uniquement la colonne ID indexée.

Pour la version pondérée: https://stackoverflow.com/a/41577458/893432

15
Ali

Du livre:

Choisir une ligne aléatoire en utilisant un décalage

Une autre technique permettant d’éviter les problèmes rencontrés dans les variantes précédentes consiste à compter les lignes de l’ensemble de données et à renvoyer un nombre aléatoire compris entre 0 et le nombre. Ensuite, utilisez ce nombre comme décalage lorsque vous interrogez le jeu de données.

<?php
$Rand = "SELECT ROUND(Rand() * (SELECT COUNT(*) FROM Bugs))";
$offset = $pdo->query($Rand)->fetch(PDO::FETCH_ASSOC);
$sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->execute( $offset );
$Rand_bug = $stmt->fetch();

tilisez cette solution lorsque vous ne pouvez pas assumer des valeurs de clé contiguës et que vous devez vous assurer que chaque ligne a une chance égale d'être sélectionnée.

13
zloctb

Comment sélectionner des lignes aléatoires dans une table:

À partir d'ici: Sélectionnez des lignes aléatoires dans MySQL

Une amélioration rapide par rapport à "l'analyse de la table" consiste à utiliser l'index pour récupérer des identifiants aléatoires.

SELECT *
FROM random, (
        SELECT id AS sid
        FROM random
        ORDER BY Rand( )
        LIMIT 10
    ) tmp
WHERE random.id = tmp.sid;
7
user1931858

Eh bien, si vos touches ne sont pas vides et qu’elles sont toutes numériques, vous pouvez calculer des nombres aléatoires et sélectionner ces lignes. mais ce ne sera probablement pas le cas.

Donc, une solution serait la suivante:

SELECT * FROM table WHERE key >= FLOOR(Rand()*MAX(id)) LIMIT 1

ce qui assurera fondamentalement que vous obtenez un nombre aléatoire dans la plage de vos clés et ensuite vous sélectionnez le prochain meilleur qui est plus grand. vous devez le faire 10 fois.

cependant, ceci n'est PAS vraiment aléatoire car vos clés ne seront probablement pas distribuées de manière égale.

C’est vraiment un gros problème qui n’est pas facile à résoudre et qui répond à toutes les exigences. Rand () de MySQL est ce que vous pouvez obtenir de mieux si vous voulez vraiment 10 lignes aléatoires.

Il existe cependant une autre solution rapide, mais qui présente également un compromis en matière d’aléatoire, mais qui peut vous convenir mieux. Lisez à ce sujet ici: Comment puis-je optimiser la fonction ORDER BY Rand () de MySQL?

La question est de savoir comment vous en avez besoin au hasard.

Pouvez-vous expliquer un peu plus pour que je puisse vous donner une bonne solution.

Par exemple, une entreprise avec laquelle je travaillais avait une solution qui nécessitait une rapidité absolue absolue. Ils ont fini par pré-renseigner la base de données avec des valeurs aléatoires sélectionnées en ordre décroissant, puis à nouveau définies sur des valeurs aléatoires différentes.

Si vous ne mettez presque jamais à jour, vous pouvez également renseigner un identifiant incrémenté afin de ne pas laisser d’espace vide et de calculer des clés aléatoires avant de sélectionner ... Cela dépend du cas d’utilisation!

6
The Surrican

J'avais besoin d'une requête pour retourner un grand nombre de lignes aléatoires à partir d'une table assez grande. C'est ce que je suis venu avec. D'abord, obtenez l'ID d'enregistrement maximum:

SELECT MAX(id) FROM table_name;

Puis remplacez cette valeur par:

SELECT * FROM table_name WHERE id > FLOOR(Rand() * max) LIMIT n;

Où max est l'ID d'enregistrement maximum dans la table et n le nombre de lignes que vous souhaitez dans votre jeu de résultats. L'hypothèse est qu'il n'y a pas de lacunes dans les identifiants d'enregistrement, bien que je doute que cela affecte le résultat s'il n'y en avait pas (je ne l'ai pas essayé cependant). J'ai également créé cette procédure stockée pour être plus générique; transmettez le nom de la table et le nombre de lignes à renvoyer. J'utilise MySQL 5.5.38 sous Windows 2008, 32 Go, double 3GHz E5450, et sur une table de 17 361 264 lignes, il est relativement cohérent à environ 0,03 s/11 s pour renvoyer 1 000 000 de lignes. (les temps sont tirés de MySQL Workbench 6.1; vous pouvez également utiliser CEIL au lieu de FLOOR dans la deuxième instruction select, selon vos préférences)

DELIMITER $$

USE [schema name] $$

DROP PROCEDURE IF EXISTS `random_rows` $$

CREATE PROCEDURE `random_rows`(IN tab_name VARCHAR(64), IN num_rows INT)
BEGIN

SET @t = CONCAT('SET @max=(SELECT MAX(id) FROM ',tab_name,')');
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @t = CONCAT(
    'SELECT * FROM ',
    tab_name,
    ' WHERE id>FLOOR(Rand()*@max) LIMIT ',
    num_rows);

PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$

puis

CALL [schema name].random_rows([table name], n);
3
user2406626

J'ai utilisé ceci http://jan.kneschke.de/projects/mysql/order-by-Rand/ posté par Riedsio (j'ai utilisé le cas d'une procédure stockée qui renvoie une ou plusieurs valeurs aléatoires) :

   DROP TEMPORARY TABLE IF EXISTS rands;
      CREATE TEMPORARY TABLE rands ( Rand_id INT );

    loop_me: LOOP
        IF cnt < 1 THEN
          LEAVE loop_me;
        END IF;

        INSERT INTO rands
           SELECT r1.id
             FROM random AS r1 JOIN
                  (SELECT (Rand() *
                                (SELECT MAX(id)
                                   FROM random)) AS id)
                   AS r2
            WHERE r1.id >= r2.id
            ORDER BY r1.id ASC
            LIMIT 1;

        SET cnt = cnt - 1;
      END LOOP loop_me;

Dans l'article, il résout le problème de lacunes dans les identifiants, ce qui provoque des résultats peu aléatoires en maintenant une table (en utilisant des triggers, etc ... voir l'article); Je résous le problème en ajoutant une autre colonne à la table, contenant des nombres contigus, en partant de 1 ( edit: cette colonne est ajoutée à la table temporaire créée par la sous-requête à l'exécution, n'affecte pas votre table permanente):

   DROP TEMPORARY TABLE IF EXISTS rands;
      CREATE TEMPORARY TABLE rands ( Rand_id INT );

    loop_me: LOOP
        IF cnt < 1 THEN
          LEAVE loop_me;
        END IF;

        SET @no_gaps_id := 0;

        INSERT INTO rands
           SELECT r1.id
             FROM (SELECT id, @no_gaps_id := @no_gaps_id + 1 AS no_gaps_id FROM random) AS r1 JOIN
                  (SELECT (Rand() *
                                (SELECT COUNT(*)
                                   FROM random)) AS id)
                   AS r2
            WHERE r1.no_gaps_id >= r2.id
            ORDER BY r1.no_gaps_id ASC
            LIMIT 1;

        SET cnt = cnt - 1;
      END LOOP loop_me;

Je peux voir dans l'article qu'il s'est donné beaucoup de mal pour optimiser le code; Je ne sais pas si/dans quelle mesure mes modifications ont un impact sur la performance mais fonctionnent très bien pour moi.

3
bogdan

Voici un changeur de jeu qui peut être utile pour beaucoup;

J'ai une table avec 200k lignes, avec les identifiants séquentiels, je devais choisir N des lignes aléatoires, alors j'opte pour générer des valeurs aléatoires basées sur le plus grand ID de la table, j'ai créé ce script afin de déterminer l'opération la plus rapide:

logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();

Les résultats sont:

  • Nombre: 36.8418693542479 ms
  • Max: 0.241041183472 ms
  • Ordre: 0.216960906982 ms

Basé sur ces résultats, ordre desc est l'opération la plus rapide pour obtenir l'identifiant maximal,
Voici ma réponse à la question:

SELECT GROUP_CONCAT(n SEPARATOR ',') g FROM (
    SELECT FLOOR(Rand() * (
        SELECT id FROM tbl ORDER BY id DESC LIMIT 1
    )) n FROM tbl LIMIT 10) a

...
SELECT * FROM tbl WHERE id IN ($result);

Pour votre information: Pour obtenir 10 lignes aléatoires d'une table de 200 Ko, il m'a fallu 1,78 ms (y compris toutes les opérations du côté php)

2
Toni Almeida

C'est très rapide et 100% aléatoire, même si vous avez des lacunes.

  1. Comptez le nombre xname___de lignes que vous avez disponible SELECT COUNT(*) as rows FROM TABLE
  2. Choisissez 10 nombres aléatoires distincts a_1,a_2,...,a_10 compris entre 0 et xname__
  3. Interrogez vos lignes comme suit: SELECT * FROM TABLE LIMIT 1 offset a_i pour i = 1, ..., 10

J'ai trouvé ce hack dans le livre SQL Antipatterns de Bill Karwin.

2
Adam

J'ai amélioré la réponse de @Riedsio. C’est la requête la plus efficace que je puisse trouver sur une grande table uniformément répartie avec des espaces (testée sur l’obtention de 1 000 lignes aléatoires dans une table contenant plus de 2,6 milliards de lignes).

(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max := (SELECT MAX(id) FROM table)) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1)

Laissez-moi déballer ce qui se passe.

  1. @max := (SELECT MAX(id) FROM table)
    • Je calcule et enregistre le max. Pour les très grandes tables, il y a une légère surcharge pour le calcul de MAX(id) chaque fois que vous avez besoin d'une ligne.
  2. SELECT FLOOR(Rand() * @max) + 1 as Rand)
    • Obtient un identifiant aléatoire
  3. SELECT id FROM table INNER JOIN (...) on id > Rand LIMIT 1
    • Cela comble les lacunes. Fondamentalement, si vous sélectionnez au hasard un nombre dans les espaces, il vous suffira de choisir l'id suivant. En supposant que les lacunes soient uniformément réparties, cela ne devrait pas poser de problème.

Faire l'union vous aide à tout intégrer dans 1 requête afin que vous puissiez éviter de faire plusieurs requêtes. Il vous permet également d'économiser le temps système associé au calcul de MAX(id). En fonction de votre application, cela peut avoir beaucoup d’importance ou très peu.

Notez que cela n'obtient que les identifiants et les obtient dans un ordre aléatoire. Si vous voulez faire quelque chose de plus avancé, je vous recommande de faire ceci:

SELECT t.id, t.name -- etc, etc
FROM table t
INNER JOIN (
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max := (SELECT MAX(id) FROM table)) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1) UNION
    (SELECT id FROM table INNER JOIN (SELECT FLOOR(Rand() * @max) + 1 as Rand) r on id > Rand LIMIT 1)
) x ON x.id = t.id
ORDER BY t.id
2
Hans Z

Toutes les meilleures réponses ont déjà été postées (principalement celles qui font référence au lien http://jan.kneschke.de/projects/mysql/order-by-Rand/ ).

Je veux identifier une autre possibilité d'accélération - la mise en cache . Pensez à pourquoi vous devez obtenir des lignes aléatoires. Vous souhaitez probablement afficher des annonces ou des annonces aléatoires sur un site Web. Si vous obtenez 100 req/s, est-il vraiment nécessaire que chaque visiteur obtienne des lignes aléatoires? Habituellement, il est tout à fait correct de mettre en cache ces X lignes aléatoires pendant 1 seconde (voire 10 secondes). Peu importe que 100 visiteurs uniques dans la même 1 seconde reçoivent les mêmes messages aléatoires, car la seconde suivante, 100 autres visiteurs recevront un ensemble différent de messages.

Lorsque vous utilisez cette mise en cache, vous pouvez également utiliser une partie de la solution la plus lente pour récupérer les données aléatoires, car elles ne seront extraites de MySQL qu'une fois par seconde, quel que soit votre taux de requête/s.

2
Marki555

Si vous voulez un enregistrement aléatoire (peu importe s'il y a des espaces entre les identifiants):

PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
        FLOOR(Rand() * COUNT(*))
    FROM `table_name`);

EXECUTE stmt USING @count;

Source: https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/#comment-1266

1
Junaid Atari

Si vous n'avez qu'une seule demande de lecture

Combinez la réponse de @redsio avec une table temporaire (600 Ko, ce n'est pas beaucoup):

DROP TEMPORARY TABLE IF EXISTS tmp_randorder;
CREATE TABLE tmp_randorder (id int(11) not null auto_increment primary key, data_id int(11));
INSERT INTO tmp_randorder (data_id) select id from datatable;

Et ensuite, prenez une version de @redsios Answer:

SELECT dt.*
FROM
       (SELECT (Rand() *
                     (SELECT MAX(id)
                        FROM tmp_randorder)) AS id)
        AS rnd
 INNER JOIN tmp_randorder rndo on rndo.id between rnd.id - 10 and rnd.id + 10
 INNER JOIN datatable AS dt on dt.id = rndo.data_id
 ORDER BY abs(rndo.id - rnd.id)
 LIMIT 1;

Si la table est grande, vous pouvez tamiser sur la première partie:

INSERT INTO tmp_randorder (data_id) select id from datatable where Rand() < 0.01;

Si vous avez plusieurs demandes de lecture

  1. Version: Vous pouvez garder la table tmp_randorder persistante, appelez-la datatable_idlist. Recréez cette table à certains intervalles (jour, heure), car il y aura également des trous. Si votre table devient vraiment grande, vous pouvez également remplir des trous

    sélectionnez l.data_id en tant que tout dans datatable_idlist l joint gauche datatable dt sur dt.id = l.data_id où dt.id est null;

  2. Version: attribuez à votre ensemble de données une colonne random_sortorder soit directement dans datatable, soit dans une table supplémentaire persistante datatable_sortorder. Indexez cette colonne. Générez une valeur aléatoire dans votre application (je l'appellerai $Rand).

    select l.*
    from datatable l 
    order by abs(random_sortorder - $Rand) desc 
    limit 1;
    

Cette solution distingue les "lignes Edge" avec les ordres random_sort les plus élevés et les plus bas. Réorganisez-les donc par intervalles (une fois par jour).

1
flaschenpost

Une autre solution simple consisterait à classer les lignes et à extraire l'une d'elles de manière aléatoire. Grâce à cette solution, vous n'avez pas besoin de colonne basée sur un "Id" dans la table.

SELECT d.* FROM (
SELECT  t.*,  @rownum := @rownum + 1 AS rank
FROM mytable AS t,
    (SELECT @rownum := 0) AS r,
    (SELECT @cnt := (SELECT Rand() * (SELECT COUNT(*) FROM mytable))) AS n
) d WHERE rank >= @cnt LIMIT 10;

Vous pouvez modifier la valeur limite en fonction de votre besoin d'accéder à autant de lignes que vous le souhaitez, mais il s'agirait généralement de valeurs consécutives.

Cependant, si vous ne voulez pas de valeurs aléatoires consécutives, vous pouvez extraire un échantillon plus volumineux et en choisir une au hasard. quelque chose comme ...

SELECT * FROM (
SELECT d.* FROM (
    SELECT  c.*,  @rownum := @rownum + 1 AS rank
    FROM buildbrain.`commits` AS c,
        (SELECT @rownum := 0) AS r,
        (SELECT @cnt := (SELECT Rand() * (SELECT COUNT(*) FROM buildbrain.`commits`))) AS rnd
) d 
WHERE rank >= @cnt LIMIT 10000 
) t ORDER BY Rand() LIMIT 10;
1
sactiw

Une façon que je trouve très bonne s'il existe un identifiant généré automatiquement consiste à utiliser l'opérateur modulo '%'. Par exemple, si vous avez besoin de 10 000 enregistrements aléatoires sur 70 000, vous pouvez simplifier les choses en indiquant qu'il vous faut 1 ligne sur 7. Ceci peut être simplifié dans cette requête:

SELECT * FROM 
    table 
WHERE 
    id % 
    FLOOR(
        (SELECT count(1) FROM table) 
        / 10000
    ) = 0;

Si le résultat de la division des lignes cibles par le total disponible n'est pas un entier, vous aurez des lignes supplémentaires par rapport à ce que vous avez demandé. Vous devez donc ajouter une clause LIMIT pour vous aider à ajuster le jeu de résultats de la manière suivante:

SELECT * FROM 
    table 
WHERE 
    id % 
    FLOOR(
        (SELECT count(1) FROM table) 
        / 10000
    ) = 0
LIMIT 10000;

Cela nécessite une analyse complète, mais il est plus rapide que ORDER BY Rand et, à mon avis, plus simple à comprendre que les autres options mentionnées dans ce fil. De même, si le système qui écrit dans la base de données crée des ensembles de lignes par lots, le résultat obtenu peut ne pas être aussi aléatoire que prévu.

1
Nicolas Cohen

Les éléments suivants doivent être rapides, impartiaux et indépendants de la colonne id. Cependant, cela ne garantit pas que le nombre de lignes renvoyées correspondra au nombre de lignes demandées.

SELECT *
FROM t
WHERE Rand() < (SELECT 10 / COUNT(*) FROM t)

Explication: en supposant que vous vouliez 10 lignes sur 100, chaque ligne a 1 probabilité sur 10 d'être séléctionné, ce qui pourrait être obtenu avec WHERE Rand() < 0.1. Cette approche ne garantit pas 10 lignes; mais si la requête est exécutée suffisamment de fois, le nombre moyen de lignes par exécution sera d'environ 10 et chaque ligne de la table sera sélectionnée de manière égale.

0
Salman A

J'ai parcouru toutes les réponses et je ne pense pas que quiconque ait mentionné cette possibilité, et je ne sais pas pourquoi.

Si vous voulez une simplicité et une rapidité maximales, à un coût minime, alors il me semble logique de stocker un nombre aléatoire contre chaque ligne de la base de données. Créez simplement une colonne supplémentaire, random_number, et définissez sa valeur par défaut sur Rand(). Créez un index sur cette colonne.

Ensuite, lorsque vous souhaitez récupérer une ligne, générez un nombre aléatoire dans votre code (PHP, Perl, peu importe) et comparez-le à la colonne.

SELECT FROM tbl WHERE random_number >= :random LIMIT 1

Je suppose que même si c'est très bien pour une seule rangée, pour dix rangées comme l'OP l'a demandé, il faudrait l'appeler dix fois (ou trouver un astucieux Tweak qui m'échappe immédiatement)

0
Codemonkey