Я пытаюсь сделать эффективный SQL-код для MySQL, чтобы получить некоторые значения, но в случайном порядке и в разной сумме. Проблема в том, что таблицы довольно большие (~ 4 м строк, ~ 400 МБ), и у меня нет много времени для этого (на данный момент для каждой попытки требуется около 1-2 минут). Кроме того, есть индекс для каждого из столбцов, но не UNIQUE, и это строковое значение, а не auto-inc val.MySQL: UNION и многие ORDER BY RANDOM
производящая Im длинный SQL запрос:
(SELECT fieldA,'id1' AS id FROM myTable WHERE (fieldB LIKE 'xxxx:%') ORDER BY RAND() LIMIT 7)
UNION ALL
(SELECT fieldA,'id2' AS id FROM myTable WHERE (fieldB ='123123') ORDER BY RAND() LIMIT 5)
etc...
Я хотел бы заказать эту таблицу только один раз (это занимает так много времени). Я уже пробовал:
- даже временные таблицы (не успех, это не займет слишком много времени, чтобы скопировать всю таблицу),
- MySQL UNION 2 queries containing ORDER BYs,
- How to quickly re-sort a MySQL table by one of the columns?,
- How to quickly SELECT 3 random records from a 30k MySQL table with a where filter by a single query?
и У меня была только удача с последним (предложение III от OP), но «магическое» число из 16 не делает трюка - это хорошо для небольших таблиц, а не для таблиц с ~ 4000000 строк.
Это Ouput образца EXPLAIN:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY myTable range fieldB fieldB 143 NULL 64198 Using where; Using temporary; Using filesort
2 UNION myTable ALL NULL NULL NULL NULL 4386943 Using where; Using temporary; Using filesort
3 UNION myTable range fieldB fieldB 143 NULL 34374 Using where; Using temporary; Using filesort
4 UNION myTable ref fieldB fieldB 143 const 1999 Using where; Using temporary; Using filesort
5 UNION myTable range fieldB fieldB 143 NULL 1 Using where; Using temporary; Using filesort NULL
UNION RESULT <union1,2,3,4,5> ALL NULL NULL NULL NULL NULL
Так что я думаю, что ORDER BY RAND главная проблема - это «Использование временного, используя FileSort» для каждого UNION частей.
определение Таблица:
CREATE TABLE IF NOT EXISTS `myTable` (
`fieldA` varchar(42) NOT NULL,
`XYZ` varchar(36) NOT NULL,
`fieldB` varchar(47) NOT NULL,
KEY `fieldA` (`fieldA`),
KEY `XYZ` (`XYZ`),
KEY `fieldB` (`fieldB`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Он хранит только простые, короткие строки, но многие из них.
Любые советы, meaby есть другой подход?
@edit, прямо сейчас Im используя как MySQL и PHP для того чтобы достигнуть его:
Im получения списка обязательных для заполнения значений FieldB, сделав союзы
SELECT fieldB, "xxxx:%" AS orygLike FROM myTable WHERE fieldB LIKE "xxxx:%" GROUP BY fieldB
и т.д. для каждого UNIONed query - только для тех, кто находится в режиме LIKE, если это «=», я уже знаю, какое поле B является действительным :)
Затем Im удалось создать массив сопоставления fieldBVal => orygLIKE (например,
"xxxx:yyyy"=>"xxxx:%"
)Я перечисляю ВСЕ ИДЫ поля А, которые могут использоваться по ID, используя
WHERE id IN (id1,id2,id3...)
- таким образом у меня есть все ID, которые могут быть использованы. Прямо здесь Im объединяет массивы вместе и выбирает случайные идентификаторы с array_rand.Простой:
SELECT * FROM myTable WHERE id IN (RndID1, RndID2, RndID3 etc...)
его очень быстро и дает хорошие результаты :)
Благодаря fancyPants за указание о ID автоматического вкл поле
Вы пытались использовать EXPLAIN? вы, вероятно, сможете увидеть, где ваш запрос не использует индексы, и вы, вероятно, могли бы что-то сделать соответствующим образом. –
Да, включите его в мой вопрос. –
~ 400 МБ? Вы сохраняете изображения как BLOBS в реальной базе данных? Если это так, подумайте о сохранении их в отдельной таблице приложений. – Strawberry