mam taki problem: chcę wrzucić do tabeli 16 milionów rekordów zawierających losowe unikalne liczby z wybranego zakresu.
Tabela jest prosta:
CREATE TABLE `codes` ( `code_id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `code` bigint(20) UNSIGNED NOT NULL, `is_used` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`code_id`), UNIQUE KEY `code` (`code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
I teraz... Stworzyłem funkcję, która na wejściu ma zakres (min, max) oraz ilość rekordów, a która generuje losowe liczby i zapisuje je do tabeli. Działa na zasadzie dopełnienia liczby rekordów do wymaganej ilości.
DELIMITER $$ CREATE DEFINER=`root`@`localhost` FUNCTION `codes`(`minRange` BIGINT UNSIGNED, `maxRange` BIGINT UNSIGNED, `_amount` BIGINT UNSIGNED) RETURNS tinyint(1) MODIFIES SQL DATA BEGIN DECLARE pick BIGINT; while (SELECT count(*) FROM codes) < _amount do begin SET pick = minRange + FLOOR(RAND() * (maxRange - minRange + 1)); INSERT IGNORE INTO codes (code) VALUES (pick); end; end while; RETURN 1; END$$ DELIMITER ;
Funkcja jest meganieoptymalna, bo za każdym przejściem pętli sprawdza, ile jest już rekordów w tabeli i kontynuuje działanie, dopóki nie zostanie osiągnięta docelowa liczba rekordów. Czas wstawiania 20 000 rekordów z zakresu 1 000 000 000 - 9 999 999 999 (zależy mi na liczbach 10-cyfrowych) to 2,5 minuty. Wstawienie 16 milionów rekordów to szacunkowo 33 godziny.
Druga funkcja działa na zasadzie wstawienia określonej liczby rekordów (nie dopełnienia):
DELIMITER $$ -- -- Funkcje -- CREATE DEFINER=`root`@`localhost` FUNCTION `codes`(`minRange` BIGINT UNSIGNED, `maxRange` BIGINT UNSIGNED, `_amount` BIGINT UNSIGNED) RETURNS tinyint(1) MODIFIES SQL DATA BEGIN DECLARE pick BIGINT; DECLARE i BIGINT; SET i = 1; while i <= _amount do begin SET pick = minRange + FLOOR(RAND() * (maxRange - minRange + 1)); INSERT IGNORE INTO codes (code) VALUES (pick); SET i = i+1; end; end while; RETURN 1; END$$ DELIMITER ;
Funkcja jest o niebo szybsza, 20 000 rekordów to ~1 sek. Wada: nie zawsze wstawi wymaganą liczbę rekordów, bo nie ma sprawdzania, ile jest rekordów w tabeli, a jest INSERT IGNORE, żeby uniknąć duplikatów.
To co chciałbym osiągnąć, to optymalizacja pierwszej funkcji - tak, żeby dopełniła mi tabelę do wymaganej liczby rekordów. Będę wdzięczny za wskazówki.