Visualizzazione dei risultati da 1 a 6 su 6
  1. #1
    Utente di HTML.it L'avatar di nicola75ss
    Registrato dal
    Nov 2004
    Messaggi
    12,922

    [mysql] selezionare N record casuali per gruppo

    Ciao a tutti e buona domenica.
    Come da titolo mi trovo a dover risolvere il problema della selezione di un tot numero di record da ciascun gruppo in modo casuale.

    Mi son guardato un pò intorno e ho trovato questo thread:

    http://forums.mysql.com/read.php?10,...130#msg-274130

    La soluzione fornita da laptop alias è impraticabile su grosse tabelle.

    Per quel che riguarda la selezione casuale di record, la soluzione più efficiente che abbia trovato finora è questa qui:

    http://explainextended.com/2009/03/0...g-random-rows/

    Partendo da quella query ho creato questa stored procedure:

    codice:
    delimiter //
    drop procedure if exists casualiPerGruppo //
    create procedure casualiPerGruppo(in tabella varchar(50),in campo varchar(50),in numPerGruppo int)
    comment 'Selezione di N record casuali per gruppo'
    begin
    declare elenco_campi varchar(255);
    declare valore int;
    declare finite int default 0;
    declare query1 varchar(250);
    declare query2 varchar(250);
    declare query3 varchar(250);
    declare query4 varchar(250);
    declare cur_gruppi cursor for select gruppo from tmp_view;
    declare continue handler for not found set finite = 1;
    
    drop table if exists tmp_casuali;
    set @query1 = concat('create temporary table tmp_casuali like ', tabella);
    prepare stmt from @query1;
    execute stmt;
    deallocate prepare stmt;
    
    set @query2 = concat('create or replace view tmp_view as select ',campo,' as gruppo from ',tabella,' group by ',campo);
    prepare stmt from @query2;
    execute stmt;
    deallocate prepare stmt;
    
    open cur_gruppi;
    mio_loop:loop
    fetch cur_gruppi into valore;
    	if finite = 1 then
    		leave mio_loop;
    	end if;
    
    set @query3 = concat("select group_concat(column_name) into @elenco_campi
    		      from information_schema.columns
                          where table_name = '",tabella,"' and table_schema = database()");
    prepare stmt from @query3;
    execute stmt;
    deallocate prepare stmt;
    
    set @query4 = concat('insert into tmp_casuali select ',
    		     @elenco_campi,' from (
    				     select  @cnt := count(*) + 1,
    				     @lim :=', numPerGruppo,
    			             ' from ',tabella,
    				     ' where ',campo,' = ', valore,
    				     ' ) vars
    				     straight_join
    					(
    					select  r.*,
    					@lim := @lim - 1
    					from ', tabella, ' r
    					where   (@cnt := @cnt - 1)
    					and rand() < @lim / @cnt and ', campo, ' = ', valore ,
    					') i');
    
    prepare stmt from @query4;
    execute stmt;
    deallocate prepare stmt;
    
    end loop;
    close cur_gruppi;
    select * from tmp_casuali;
    end //
    delimiter ;
    che poi richiamo così:

    codice:
    create table prova (
    id int not null auto_increment primary key,
    id_gruppo int,
    altro varchar(10)
    ) engine = myisam;
    
    
    insert into prova (id_gruppo,altro) values 
    (1,'aaa'),(2,'bbb'),(3,'ccc'),(1,'ddd'),(1,'eee'),(2,'fff'),
    (2,'ggg'),(2,'hhh'),(3,'iii'),(3,'jjj'),(3,'kkk'),(1,'lll'),(4,'mmm');
    
    call casualiPerGruppo('prova','id_gruppo',2);
    La query di Quassnoi per quanto geniale e performante, su qualche milione di record mi richiede anche più di un secondo. Se poi vado a richiamarla più volte sui vari gruppi i tempi logicamente si allungano ulteriormente.

    Qual è secondo voi il miglior approccio a questo problema?
    Grazie a tutti.

  2. #2
    Mah...forse può convenire prima calcolare i "random" e poi fare la query?
    Tipo:
    rand_ids = calcola_random
    query = select x from y where z in (rand_ids)
    Però non so se può davvero migliorare la situazione

  3. #3

  4. #4
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    1,469
    sono impegnatissimo per una consegna: se non hai fretta la prox settimana "mi scateno"

  5. #5
    Utente di HTML.it L'avatar di nicola75ss
    Registrato dal
    Nov 2004
    Messaggi
    12,922
    Hi Quassnoi. Thanks for taking the time to register here.
    I read the article you linked me. Your query is very fast but it returns first N row per group and I don't understand how I can adapt it to my problem in order to have N random rows per group.

    @franzauker: Non ho nessuna fretta, ci mancherebbe altro. Ogni aiuto sarà ben accetto.

  6. #6
    Utente di HTML.it
    Registrato dal
    Jan 2011
    Messaggi
    1,469
    Originariamente inviato da nicola75ss
    @franzauker: Non ho nessuna fretta, ci mancherebbe altro. Ogni aiuto sarà ben accetto.
    ho appena rilasciato un aggiornamento del mio gestionale... se domani non ci sono "disastri"... vedremo...
    intanto perchè non carichi un dump di prova compresso da qualche parte per poter fare raffronti quantitativi sulla stessa base?

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.