SQL baze podataka - Sponzor: Baze-Podataka.net MySQL, MSSQL, Oracle, Access, ODBC. Ako imate problem brže i preciznije ćete dobiti odgovor ako priložite strukturu tabela ili skript koji kreira tabele i puni ih test podacima umesto što to problem opisujete samo rečima. Sponzor: Baze-Podataka.net - Blog o bazama podataka |
|
Alati teme | Način prikaza |
08. 04. 2008. | #1 |
133t
Master
|
random select na velikoj tabeli
problem:
imam tabelu (~2M unosa), primarni kljuch je polje id, medjutim ono nije uniformno rasporedjeno, tj postoje veliki blokovi obrisanih unosa, naprimer id moze da ide: 1 2 3 434 454 455 456 900 901 . . . i tako, e sad meni treba query koji ce na najbrzi nacin da mi vrati recimo 2000 random row-ova iz tablele (tih 2000 moraju biti unikatni) any idea? (mySQL) P.S. znam za ORDER BY RAND() LIMIT XYZ ali je to jako sporo, i ima tendenciju da ubije cpu Poslednja izmena od kodi : 08. 04. 2008. u 15:14. |
08. 04. 2008. | #2 |
Ivan Dilber
Sir Write-a-Lot
|
mozes da smanjis broj recorda koji se sortiraju tako sto ces da stavis:
"WHERE id BETWEEN ". $rand ." AND ". ($rand+10000) ." ORDER BY RAND() LIMIT XYZ" ako 10000 nije dovoljno stavis vecu granicu
__________________
Leadership is the art of getting people to want to do what you know must be done. |
08. 04. 2008. | #3 |
133t
Master
|
hmm...
to bi definitivno smanjilo vreme, i olaksalo stvari, ali bi onda favorizovalo unose iz tih 10k, sto na 2M unosa nije naivno.. a ako povecam na recimo 100k opet ce trajati mnogo taj query evo sad googlam, i izgleda da uopste nema lakog resenja za ovaj problem.. jel ima neko neku ideju, ili sam osudjen na dodatno polje sa sekvencom koja ce se updejtovati na svaki insert i delete |
08. 04. 2008. | #4 |
Vladan Zirojević
Grand Master
|
http://akinas.com/pages/en/blog/mysql_random_row/
Valjda Solution 3 na toj strani pokriva i tvoj slucaj... Poslednja izmena od zira : 08. 04. 2008. u 15:58. |
08. 04. 2008. | #5 |
Ivan Dilber
Sir Write-a-Lot
|
@zira: ovaj primer dohvat samo jedan rekord
@kodi: mozes da umesto jednog opsega od 10000 rekorda dohvatis par manjih (5-6 recimo, ili koliko mislis da ti treba), pa da ih unijom spojis, pa onda na celom rezultatu uradis ORDER BY rand() u sustini, ovde ti je pitanje jel ti treba stroga uniformna raspodela verovatnoce, ili ti treba brzina, treba naci neki najbolji odnos..
__________________
Leadership is the art of getting people to want to do what you know must be done. |
08. 04. 2008. | #6 | |
133t
Master
|
Citat:
trabaju mi oba odustao sam od uniformne raspodele, i posto ti blokovi obrisanih podataka nisu toliko veliki uradio sam varijantu da prvo u phpu generishem niz sa offsetima a onda fetchujem sa where id >=$offset, radi prilichno brzo.... Off Topic: btw, radi se o gomili keyworda, cije rezultate sa googla treba da updatujem i da sve bude mladje od 10 dana, u medjuvremenu je dataset bash narastao, tako da smo preshli na model gde se na svakihsat vremena updejtuje deo sadrzaja, a onda na svakih 10 dana pokrene skripta koja pokupi sve sto je po timestamp-u starije od 10dana, obichno ostane manje od procenat onoga sto se ovakvom metodom promashi, a generalno podaci budu mnogo sveziji, samo treba nashtelovati koliku porciju da uzima pri svakom prolazu i koliko chesto to da ide eto mozda nekome bude korisno... Poslednja izmena od kodi : 08. 04. 2008. u 20:51. |
|
08. 04. 2008. | #7 |
Pilece krilce(reš)
Master
|
evo dodjosmo do ovoga
PHP kôd:
|
08. 04. 2008. | #8 |
133t
Master
|
nisam siguran da razumem najbolje ovo, ovo mi vrati samo xyz id-jeva.. opet bih morao da radim fetch za svaki od njih, a i cini mi se da je moguce da mi vrati id koji je recimo izbrisan (?) ili greshim ?
|
08. 04. 2008. | #9 |
Ivan Dilber
Sir Write-a-Lot
|
A mozda moze da se naprosto izgenerise jedno 4000 random brojeva (lepa okrugla cifra), i onda uradis:
SELECT * FROM tabela WHERE id IN ($gomila_rnd_brojeva) ORDER BY RAND() LIMIT 2000; Ako ti se ne vrati dovoljno rezultata uradis naprosto ponovo upit sa korigovanim limitom, i tako sve dok ne skupis dovoljno...
__________________
Leadership is the art of getting people to want to do what you know must be done. |
09. 04. 2008. | #10 |
old school
Professional
|
Nadam se da ovaj kôd govori sve sam od sebe i da ne moram komentarisati nista
Kôd:
use test; create table keywords ( id int unsigned not null auto_increment, keyword varchar(32) not null, url varchar(255), primary key(id) ); DELIMITER $$ DROP PROCEDURE IF EXISTS test.unesi_podatke $$ CREATE PROCEDURE test.unesi_podatke(IN koliko INT) BEGIN DECLARE brojac INT DEFAULT 1; while brojac <= koliko do INSERT INTO keywords (id, keyword, url) VALUES(NULL, CONCAT('keyword_', brojac), CONCAT('http://www.url', brojac, '.com')); set brojac = brojac + 1; end while; END $$ DELIMITER ; mysql> create table keywords ( -> id int unsigned not null auto_increment, -> keyword varchar(32) not null, -> url varchar(255), -> primary key(id) -> ); Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER $$ mysql> DROP PROCEDURE IF EXISTS test.unesi_podatke $$ Query OK, 0 rows affected (0.03 sec) mysql> CREATE PROCEDURE test.unesi_podatke(IN koliko INT) -> BEGIN -> DECLARE brojac INT DEFAULT 1; -> while brojac <= koliko do -> INSERT INTO keywords (id, keyword, url) -> VALUES(NULL, CONCAT('keyword_', brojac), CONCAT('http://www.url', brojac, '.com')); -> set brojac = brojac + 1; -> end while; -> END $$ Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql> call test.unesi_podatke(2000000); Query OK, 1 row affected (1 min 31.95 sec) mysql> select count(*) from keywords; +----------+ | count(*) | +----------+ | 2000000 | +----------+ 1 row in set (0.00 sec) mysql> create index indeks_id on keywords(id); Query OK, 2000000 rows affected (15.28 sec) Records: 2000000 Duplicates: 0 Warnings: 0 mysql> DELETE FROM keywords WHERE mod(id, 7) = 0; Query OK, 285714 rows affected (6.06 sec) mysql> mysql> select count(*) from keywords; +----------+ | count(*) | +----------+ | 1714286 | +----------+ 1 row in set (0.00 sec) mysql> select * from keywords -> order by rand() -> limit 2000; 2000 rows in set (1 min 43.15 sec) mysql> SELECT * -> FROM keywords k -> JOIN (SELECT FLOOR( MAX(ID) * RAND()) AS Rand_ID FROM keywords) AS x -> ON k.id >= x.Rand_ID -> limit 2000; 2000 rows in set (0.63 sec) Kôd:
$sql = "SELECT * FROM keywords k JOIN (SELECT FLOOR( MAX(ID) * ".lcg_value().") AS Rand_ID FROM keywords) AS x ON k.id >= x.Rand_ID limit 2000"; Kôd:
mysql> SELECT * -> FROM keywords k -> JOIN (SELECT FLOOR( MAX(ID) * 0.234) AS Rand_ID FROM keywords) AS x -> ON k.id >= x.Rand_ID -> limit 2000; 2000 rows in set (0.02 sec)
__________________
Blog: Baze podataka ------------------------ Oracle OCP DBA Oracle OCE SQL Expert Oracle OCP Developer Certified MySQL DBA Poslednja izmena od Dejan Topalovic : 09. 04. 2008. u 00:48. Razlog: Dodana napomena za lcg_value() |
2 članova zahvaljuje Dejan Topalovic za poruku: |
|
|
Slične teme | ||||
Tema | Početna poruka teme | Forum | Odgovori | Poslednja poruka |
random + mysql | mega023 | PHP | 9 | 09. 03. 2010. 17:08 |
Raspored sirine celija u tabeli | misk0 | (X)HTML, JavaScript, DHTML, XML, CSS | 7 | 06. 05. 2008. 21:18 |
random koji favorizuje | kodi | Programiranje | 16 | 29. 04. 2007. 22:09 |
java.util.Random security | Ivan | Programiranje | 0 | 02. 01. 2007. 19:43 |
Random image - preraditi za flash... | headcutter | (X)HTML, JavaScript, DHTML, XML, CSS | 4 | 02. 09. 2005. 23:14 |