Оптимизация производительности MySQL запросов - PullRequest
1 голос
/ 10 февраля 2012

В моей базе данных есть словарь, содержащий более миллиона записей, и этот простой выбор

select * from Word where languageId = 'en' order by rand() limit 1

случайным образом выбирает одно слово.

Проблема в том, что этот запрос длится 3-4 секунды, что очень долго, потому что мне приходится повторять его много раз.

Есть ли способ достичь того же, но гораздо быстрее?

EDIT - схема таблицы

wordId - integer, auto increment
languageId - varchar (FK), values like cs, en, de, ... 
word - varchar, word itself

Пример структуры данных

wordId   languageId   word
--------------------------
1        cs           abatyše
...
100000   cs           zip
100001   en           aardvark
...
etc

SQL

CREATE TABLE Language (
  languageId VARCHAR(20)  NOT NULL  ,
  name VARCHAR(255)  NULL    ,
PRIMARY KEY(languageId));

CREATE TABLE Word (
  wordId INTEGER UNSIGNED  NOT NULL   AUTO_INCREMENT,
  languageId VARCHAR(20)  NOT NULL  ,
  word VARCHAR(255)  NULL    ,
PRIMARY KEY(wordId)  ,
INDEX Word_FK_Language(languageId),
  FOREIGN KEY(languageId)
    REFERENCES Language(languageId)
      ON DELETE NO ACTION
      ON UPDATE NO ACTION);

Ответы [ 3 ]

3 голосов
/ 10 февраля 2012

Если у вас есть столбец идентификаторов и промежутки между элементами невелики (не слишком много элементов было удалено, в противном случае некоторые элементы будут выбираться чаще), попробуйте этот запрос

SELECT * FROM `table` 
   WHERE id >= 
      (SELECT FLOOR( MAX(id) * RAND()) FROM `table` WHERE languageId = 'en' ) 
   AND languageId = 'en'
   ORDER BY id LIMIT 1;

И посмотрите на другие примеры здесь http://akinas.com/pages/en/blog/mysql_random_row/

ps: я только что понял, что это работает хорошо только без требования для languageId, иначе промежутки в идентификаторах для того же languageId могли бы быть огромными.

Обновлено Попробуйте, это может быть в пару раз быстрее. Я проверил это по времени выполнения вашего запроса .. в два раза быстрее ..

SELECT d.* FROM
  (SELECT @rn:=0 ) r, 
  (SELECT FLOOR(count(*)*RAND()) as rnd FROM `Word` WHERE languageId = 'en') t,  
  (SELECT @rn:=@rn+1 as rn, `Word`.* FROM `Word` WHERE languageId = 'en' ) d 
WHERE d.rn >= t.rnd LIMIT 1

в основном он все еще создает какие-то непрерывные идентификаторы, но без сортировки по ним.

Последнее обновление Это может быть даже быстрее (зависит от сгенерированного случайного числа)

SELECT d.* FROM
  ( SELECT @rn:=@rn+1 as rn, w.*, t.rnd rnd FROM 
     (SELECT @rn:=0 ) r, 
     (SELECT FLOOR(count(*)*RAND()) rnd FROM `Word` WHERE languageId = 'en') t, 
     `Word` w 
   WHERE w.languageId = 'en' AND @rn<t.rnd
  ) d 
WHERE d.rn=d.rnd
2 голосов
/ 10 февраля 2012

Во-первых, убедитесь, что ваша таблица правильно проиндексирована.У него есть первичный ключ?Является ли languageId индексом?Убедитесь, что это так.

Во-вторых, вас интересует только слово, а не такие вещи, как languageId или другие поля в таблице?Если вам это нужно, вам нужно:

SELECT word_field FROM Word...

Подстановочные знаки SELECT возвращают все, но вам не нужно извлекать данные, которые вы никогда не собираетесь использовать.

В-третьих, вы простовыполнить один и тот же запрос в цикле, если вы повторяете его много раз?Измените оператор LIMIT, чтобы он возвращал больше слов в одном запросе:

-- for 10 words
... LIMIT 10

Вы можете сохранить этот результат для дальнейшего использования без необходимости повторного запроса к базе данных.

Наконец, вы можетезапустите ваш запрос, но с EXPLAIN перед ним, чтобы получить представление о том, что делает MySQL при его запуске.

EXPLAIN SELECT word_field FROM Word...

Используя это, вы можете определить, где именно ваш запрос выполняется медленно.

0 голосов
/ 10 февраля 2012

Вы можете разбить таблицу по первой букве слова, выбрать букву случайным образом, а затем использовать существующую сортировку, чтобы выбрать случайное слово в этом разделе. На современном сервере сортировка ~ 50 000 строк должна быть достаточно быстрой. Я думаю, что большинство сортировок баз данных - это n lg (n), поэтому 1/26 записей должна сортироваться более чем в 50 раз быстрее. Выбор раздела должен быть незначительным с точки зрения производительности. С другой стороны, комментарий fuzzyDunlop о повторном использовании того же списка, несомненно, победит после примерно 50 казней. Изменить: я думаю, что я испортил свой журнал на Windows Calc, поэтому я собираюсь пойти с: это должно быть более чем в 26 раз быстрее;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...