2011-12-09 16 views
8

Rozejrzałem się i wydaje mi się, że nie ma na to łatwego sposobu. Wygląda na to, że łatwiej jest zdobyć podzbiór rekordów i wykonać cały losowy kod (perl). Metody, które widziałem w internecie wydają się być nastawione na co najwyżej setki tysięcy, ale z pewnością nie na miliony.Szybko wybierz losowy identyfikator z tabeli mysql z milionami niesekwencyjnych rekordów

Tabela, z którą pracuję ma 6 milionów rekordów (i rośnie), identyfikatory są automatycznie inkrementowane, ale nie zawsze są przechowywane w tabeli (bez odstępu).

Próbowałem wykonać polecenie LIMIT 1, które zostało polecone, ale zapytanie trwa wiecznie - czy jest na to szybki sposób, zważywszy na brak przerw w zapisie? Nie mogę po prostu wziąć maksymalnego i losowego w całym zakresie.

Aktualizacja:

Jeden pomysł miałem może było chwycić max, losowo limitu opartego na max, a następnie złapać zasięg 10 rekordów z random_limit_1 do random_limit_2 a następnie biorąc pierwszy znaleziono rekordu w tym zakresie.

A jeśli znam maksimum, czy jest sposób, że mogę po prostu wybrać piąty rekord tabeli, nie wiedząc, który to jest identyfikator. Potem chwytam identyfikator tej płyty.

Aktualizacja:

To zapytanie jest nieco szybciej-owski. Nadal nie wystarczająco szybko =/

SELECT t.id FROM table t JOIN (SELECT(FLOOR(max(id) * rand())) as maxid FROM table) as tt on t.id >= tt.maxid LIMIT 1 
+0

Co masz na myśli przez określenie "non-gapless"? Że są luki? –

+0

Tak. dokładnie to =] – qodeninja

+1

całkiem pewny nodebunny oznacza typową indeks autoIncrement że miał kilka wierszy usunięte w przeszłości ... –

Odpowiedz

5

Tak, pomysł wydaje się dobry:

select min(ID), max(ID) from table into @min, @max; 
set @range = @max - @min; 
set @mr = @min + ((@range/1000) * (rand() * 1000)); 
select ID from table 
    where ID >= @mr and ID <= @mr + 1000 
    order by rand() 
    limit 1 
-- into @result 
; 

Może zmienić 1000 do 10000 lub cokolwiek co potrzebne do skalowania .. .

EDIT: można również spróbować tego:

select ID from table 
    where (ID % 1000) = floor(rand() * 1000) 
    order by rand() 
    limit 1 
; 

Dzieli go wzdłuż różnych linii ...

EDIT 2:

Patrz: What is the best way to pick a random row from a table in MySQL?

Jest to prawdopodobnie najszybszy sposób:

select @row := floor(count(*) * rand()) from some_tbl; 
select some_ID from some_tbl limit @row, 1; 

niestety zmienne nie mogą być używane w klauzula limitów, więc musisz użyć zapytania dynamicznego, albo wpisując ciąg zapytania w kodzie, albo używając PREPARE i EXECUTE. Ponadto, limit n, 1 nadal wymaga skanowania n elementów do tabeli, więc jest tylko około dwa razy szybszy niż druga metoda wymieniona powyżej średnio. (Choć prawdopodobnie jest bardziej jednolity i gwarantuje, że zawsze znajdzie pasujące wiersze)

+0

Pobiegłem tej kwerendy, ale zwrócony zbiór pusty. – qodeninja

+0

Jeśli istnieją luki szersze niż 1000 rekordów, co może się zdarzyć ... Co dystrybucja swój identyfikator Like? –

8
SELECT * FROM TABLE ORDER BY RAND() LIMIT 1; 

Ok, to jest wolny. Jeśli będziesz szukać ORDER BY RAND() MYSQL, znajdziesz wiele wyników mówiąc, że jest to bardzo powolne i tak jest w tym przypadku. Zrobiłem trochę badań i znalazłem ten alternatywny MySQL rand() is slow on large datasets Mam nadzieję, że to jest lepsze

+0

Jesteś zbyt szybciej ........ +1 – Jomoos

+0

Tak próbowałem tego, ale to trwa Forevers dla zapytania uruchomić nawet na Limit 1. – qodeninja

+0

kwerendę na ten link SELECT t.id z tabeli t DOŁĄCZ (SELECT (podłoga (max (id) * rand())) jak maxid z tabeli) jako tt na t.id> = tt.maxid LIMIT 1 jest nieco szybciej - wciąż zbyt powolny =/ – qodeninja

0
SELECT ID 
    FROM YourTable 
    ORDER BY RAND() LIMIT 1; 
+4

spróbuj uruchomić to zapytanie w 6 milionach rekordów. bieganie trwa wiecznie. – qodeninja

Powiązane problemy