2012-03-13 6 views
1

У меня ужасное время с запросом MySQL. Я провел большую часть своих выходных и большую часть своего дня сегодня пытался сделать этот запрос немного быстрее. Я сделал это значительно быстрее, но я знаю, что смогу сделать это лучше.MySQL Query Optimization - случайная запись

SELECT m.id,other_fields,C.contacts_count FROM marketingDatabase AS m 
LEFT OUTER JOIN 
(SELECT COUNT(*) as contacts_count, rid 
    FROM contacts 
    WHERE status = 'Active' AND install_id = 'XXXX' GROUP BY rid) as C 
ON C.rid = m.id 
WHERE (RAND()*2612<50) 
    AND do_not_call != 'true' 
    AND `ACTUAL SALES VOLUME` >= '800000' 
    AND `ACTUAL SALES VOLUME` <= '1200000' 
    AND status = 'Pending' 
    AND install_id = 'XXXXX' 
ORDER BY RAND() 

У меня есть индекс «install_id», «категории» и «статус», но EXPLAIN показывает, что она разбирала на основе 9100 строк.

Моя Объяснять здесь: https://s3.amazonaws.com/jas-so-question/Screen+Shot+2012-03-13+at+12.34.04+AM.png

Кто-нибудь есть какие-либо предложения о том, что я могу сделать, чтобы сделать это немного быстрее? Вся точка запроса заключается в выборе случайной записи из записей учетной записи (install_id), которая соответствует определенным критериям, таким как объем продаж, статус и do_not_call. В настоящее время я собираю 25 записей и кеширую их (используя PHP), поэтому мне нужно запускать этот запрос только каждые 25 запросов, но я уже имею дело с тысячами запросов в день. В настоящее время он занимает 0,2 секунды. Я понимаю, что, используя ORDER BY RAND(), я уже делаю большой удар производительности, но он просто сортирует 25 строк.

Заранее благодарим за помощь.

** EDIT: Я забыл упомянуть, что индекс «contact_sort» находится в таблице «контакты» и индексирует install_id, статус и удаление. (удалить ссылки Record ID в marketingDatabase, чтобы он знал, к какой записи относится.

** EDIT 2: номер 2612 в запросе представляет количество строк в marketingDatabase, которые соответствуют критериям (install_id, статус, фактические продажи объем и т.д.)

+0

Взгляните на http://dev.mysql.com/doc/refman/5.0/ru/group-by-optimization.html Существуют ограничения и сложности, возникающие при использовании GROUP BY и индексов. Чтобы процитировать руководство «Важнейшими предпосылками для использования индексов для GROUP BY являются то, что все столбцы GROUP BY ссылаются на атрибуты из того же индекса и что индекс сохраняет свои ключи в порядке (например, это индекс BTREE, а не HASH индекс)." Вы группируете неиндексированное поле, а также выбираете и заказываете всю таблицу в подзапросе. Я думаю (не уверен), что заказ RAND() также плохая идея. – fred2

+0

ORDER BY RAND() - очень, очень [плохая идея] (http://www.webtrenches.com/post.cfm/avoid-rand-in-mysql). – budwiser

+0

Да, я знаю, что это плохая идея, хотя я читал, потому что ORDER BY RAND() только заказывает 25 строк, это не так уж и важно. Я ошибаюсь? Как я могу исправить это и все равно получить случайную запись? У меня нет столбца с автоматическим приращением без пробелов ... мой столбец id является автоматическим приращением, но имеет пробелы, где строки были удалены. – user1265617

ответ

0

Я играл вокруг с несколькими запросами, и я не думаю, что вы когда-либо быть в состоянии получить индексированные запрос для работы с RAND(), особенно когда вы используете его как в предложении WHERE, так и в предложении ORDER BY. Если это вообще возможно, я бы представил случайный элемент в моей логике PHP и, вероятно, посмотрел, имеет ли два простых запроса больше смысла, чем один довольно сложный. Кроме того, у вас есть LEFT OUTER JOIN на случайном наборе результатов, что также может увеличить объем работы, которая должна быть выполнена.

Таким образом, я бы предпочел бы - переписать исключить RAND, посмотреть, можете ли вы избавиться от LEFT OUTER JOIN. Два простых индексированных запроса с небольшим количеством PHP между ними могут быть намного лучше.

+0

Хорошо, это имеет смысл. Как я должен искать это? Запросить все записи в БД, которые соответствуют критериям, затем использовать array_rand() для выбора случайного элемента? – user1265617

+0

Сложно сказать, потому что я действительно не знаю, зачем вам нужен случайный элемент, но да, это звучит разумно. У вас всего 2612 записей, поэтому возвращение всей таблицы не слишком страшное (в зависимости от того, что в нем). По крайней мере, запрос будет кэшироваться, поэтому он будет отвлекаться от представления MySQL и, вероятно, PHP тоже. – fred2

1

Поскольку я не вижу ваши определения индекса, я не уверен, что они правильны запрос будет извлечь выгоду из следующих показателей:.

  1. композитный индекс (install_id, статус, rid) на contacts

  2. композитный индекс (install_id, статус, `АКТУАЛЬНЫЕ ПРОДАЖ VOLUME`) на marketingDatabase

+0

Да, это именно то, что я имею в настоящее время для индексов. – user1265617