За последние 24 часа нас посетили 16748 программистов и 1694 робота. Сейчас ищут 853 программиста ...

Тест-задание от TiBiDaBo

Тема в разделе "PHP и базы данных", создана пользователем Chushkin, 6 авг 2015.

  1. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    иллюстрация к моему посту выше
    Код (Text):
    1. CREATE TABLE `lions` (
    2.   `id` int(10) NOT NULL AUTO_INCREMENT,
    3.   `sex` tinyint(1) NOT NULL DEFAULT '1',
    4.   `wool` smallint(3) NOT NULL DEFAULT '1',
    5.   `color` smallint(3) NOT NULL DEFAULT '1',
    6.   PRIMARY KEY (`id`),
    7.   KEY `ix_lions_2` (`wool`,`color`)
    8. ) ENGINE=InnoDB
    нагенерил 1млн строк как
    Код (PHP):
    1. $stmt = $db->prepare("INSERT INTO `lions`(`sex`, `wool`, `color`) VALUES(?, ?, ?)");
    2. for ($i = 0; $i < 1000000; ++$i) {
    3.     $stmt->execute([
    4.         1 + $i % 2,
    5.         mt_rand(1, 100),
    6.         mt_rand(1, 100)
    7.     ]);
    8. }
    9.  
    у нас 4 возможных сочетания признаков wool и color, два из которых имеют равный приоритет.

    запрос #1 (макс. приоритет)
    Код (Text):
    1.     SELECT SQL_NO_CACHE m.`id` AS m_id, f.`id` AS f_id
    2.     FROM `lions` AS m, `lions` AS f
    3.     WHERE (m.wool = f.wool) AND (m.color = f.color) AND (m.`sex` = 1) AND (f.`sex` = 2)
    терпения не хватает дождаться завершения запроса :)
    но если добавить LIMIT 50, то time 0.002s

    mt_srand() для повторяемости результата
    SQL_NO_CACHE чтобы не одурачить себя

    теперь четырежды повторяю этот запрос (c limit) но с вариантами =/<> у wool и color и склеиваю через UNION ALL
    (... = AND =)
    U.A.
    (... = AND <>)
    U.A.
    (... <> AND =)
    U.A.
    (... <> AND <>)
    получаю за 0.036s из пула в миллион записей!
    порядок строк сохранится в порядке расстановки запросов, т.е. приоритетом 4х вариантов сочетаний я рулю как мне захочется!

    Добавлено спустя 31 минуту 39 секунд:
    Как это улучшить чтобы добиться уникальности самца и самки я еще не придумал )))

    Добавлено спустя 2 минуты 20 секунд:
    вот так можно:
    Код (Text):
    1.     SELECT SQL_NO_CACHE m.`id` AS m_id, MIN(f.`id`) AS f_id
    2.     FROM `lions` AS m, `lions` AS f
    3.     WHERE (m.wool = f.wool) AND (m.color = f.color) AND (m.`sex` = 1) AND (f.`sex` = 2)
    4.   GROUP BY m.`id`
    5.   LIMIT 50
    time 0.021s вполне приемлемо

    Добавлено спустя 12 минут 59 секунд:
    --------------------------------------------
    У меня в голове есть и абсолютно другой вариант оптимизации ;)
    У нас ограниченное число сочетаний параметров wool, color и sex. 100*100*2 = 20000.
    По условию задачи, при прочих равных нас интересуют те записи, у которых id меньше.
    Отсюда следует, что будь у нас хоть миллион, хоть 100 миллионов львов, реально в наших выборках будут присутствовать <= 20000 кандидатов.

    То есть мы можем заранее сгруппировать записи чтобы уменьшить область определения.
    Код (Text):
    1. SELECT MIN(id), wool, color, sex
    2. FROM lions
    3. GROUP BY wool, color, sex
    Мысль понятна?
     
  2. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    лев льву не пара и львица львице не пара - 10201 комбинаций.
    Только у заказчика в таблице у львиц шерсть короткая (я думаю от 0 до 10ти), а у львов длинная (например от 30 до 100)

    Мне кто-нибудь может пояснить смысл фразы
     
  3. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    Maputo, ты не о том говоришь. При чем здесь гомо/гетеро?! Математически 20000 вариантов пол+длина+цвет. Заказчик указал все возможные вариации в задании.

    Откуда ты взял про короткую шерсть? У нас условные сферические львы. Не надо додумывать типа "из жизни".
     
  4. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Понятно...
     
  5. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Вот дамп на 2000 записей http://pesow.com/F/test_09-2015-08-07.sql.gz
    Вот "правильный" универсальный/классический запрос , который даёт правильный ответ:
    Код (PHP):
    1. select t1.*, t2.*, t.rating
    2. from (
    3.   -- пересечение таблиц, что ооочень много. Квадратичная зависимость. Для 500х500 (1000 в таблице) = ~250000 чтений строк. 10 000 в таблице = ~25 млн. чтений.
    4.   select t1.id id1, (abs(t1.wool - t2.wool) + abs(t1.color - t2.color)) rating, min(t2.id) id2, count(*) c
    5.   from test_09 t1
    6.     left join test_09 t2 on t2.sex = 2 -- львицы
    7.   where t1.sex = 1 -- львы
    8.   group by t1.id, rating
    9.   order by rating, id1
    10.   limit 50 ) t
    11. left join test_09 t1 on t1.id = t.id1
    12. left join test_09 t2 on t2.id = t.id2
    artoodetoo, можете сравнить результат этого запроса с результатом Вашего метода - если равны, значит Ваш метод правильный. Скорее всего, правильный. :)
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    По невнимательности я пропустил тот факт, что значения wool и color начинаются с 0, а не с 1. То есть 101 вариант.
    Но сути это не меняет, запросы остаются те же. Просто область определения шире.

    Добавлено спустя 27 минут 8 секунд:
    Chushkin, вот с этим я не согласен:
    Код (Text):
    1. (abs(t1.wool - t2.wool) + abs(t1.color - t2.color)) rating
    разве было указание, что "расстояние" между параметрами имеет значение? Я так понял задание, что важно совпадение или несовпадение. То есть если вычислять рейтинг как число то
    Код (Text):
    1. ((t1.wool = t2.wool) + (t1.color = t2.color)) rating
    Другой повод для несовпадения результатов — указание на то, что "признаки wool и color имеют одинковый вес". То есть записи, где только один из признаков совпадает, могут стоять в любом порядке относительно друг друга, это не будет нарушением. То есть возможны разные правильные варианты ответа.
     
  7. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Не хочу постить новое сообщение. Напишу тут.
    Представьте себе таблицу на 10м записей заполненных рандомом с одинаковыми параметрами для львов и львиц.
    В ней для любого льва можно будет найти львицу со 100% совпадением перебрав для каждого не более 20402 записей.
    Запрос для такого поиска будет слишком простым.
    Вы уже убедились, что задание составлено очень грамотным человеком.
    Поэтому в таблице скорее всего нет 100% совпадающих пар, а если и есть - их должно быть значительно меньше 25 пар.
    Как заполнить таблицу в 10м записей, чтобы там было так мало идеальных пар?
    Очень просто - диапазон значений для шерсти у львов и у львиц выбрать разный.
    Вариант 1: диапазоны пересекаются
    25 пар со 100% совпадением будет легко найти
    Вариант 2(очень возможный): диапазоны имеют одно общее граничное значение (0-50, 50-100)
    В этом случае на 10 м записей (при равномерном рандоме) получается не менее 200 - 250 идеальных пар.
    Это не есть хорошо, но уменьшить принудительно это число можно
    Вариант 3 (наиболее вероятный): диапазоны значений не пересекаются.
    В этом случае можно изменить вручную 2-3 записи, чтобы было 2-3 пары со 100% совпадением.

    При самом худшем раскладе (0-50, 50-100) - для поиска наиболее подходящей пары достаточно для одной особи перебрать не более 10,3к записей. Наиболее вероятны диапазоны 0-49, 50-100 - это 10,2к записей.

    P.S.: Мне кажется нерентабельным делить таблицу на две, только ради того, чтобы в одном столбце были львы, а в другом львицы.
    P.P.S.: Я уже писал, но еще раз повторю - в задании дано четкое условие, что львы и львицы в парах должны быть уникальны.
     
  8. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Читаем задание:
    "Абсолютно подходящие пары - wool и color совпадают на 100% .
    Самые неподходящие - с максимальными различиями."
    Т.е. макс.рейтинг = abs(t1.wool - t2.wool) = 0 (это и есть "совпадение"), мин.рейтинг. = abs(t1.wool - t2.wool) = 101 (максимальное различие)
    Условие "Оба признака (wool и color) имеют одинковый вес." просто говорит о том, что не важно в каком порядке их учитывать. Т.е. рейтинг (wool=100 и color=0) = (wool=0 и color=100).
     
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    Соглашусь, что формулировка допускает толкование, но я остаюсь при мнении, что: "максимальные различия" это случай когда оба признака не равны. А 100% совпадение это когда оба признака равны.
    Не вижу указания расчитывать разницу в длине или цвете.
     
  10. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Ну, хозяин - барин.
    п.с. Кстати, надеюсь у Вас "разница" = "различие" по контексту.
     
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    Я называю разницей математическую операцию "-" ))) В тексте задания слово "разница" не встречается.
    А различием называю простой факт неравенства. Думаю, что заказчик имеет в виду то же.

    Не будем ходить вокруг да около. Кто-то должен спросить автора, ящитаю.
     
  12. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    С учётом моего понимания фразы "Абсолютно подходящие пары - wool и color совпадают на 100% .Самые неподходящие - с максимальными различиями." (т.е. от 100% до 0% совпадения), я считал степень различия. А уж в каких попугаях она считается и как - дело десятое. В данном конкретном случае, с учётом, что исходные данные целое число, оптимальны арифметические операции, я так думаю.
    И да, я уверен на 99,99%, что автор задания имел в виду "от 100% до 0%". :)
     
  13. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    ok, это достойная т.з.

    в задании есть еще место для разночтений:

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

    Могут ли в выборке присутствовать пары с одним и тем же львом, но с разной степенью подходящести и разными львицами?
    То есть такие записи:
    rate, m_id, f_id
    1, 14, 20
    1, 17, 88
    1, 78, 1020
    2, 14, 99
    2, 101, 104

    Это неочевидно.

    Добавлено спустя 6 минут 44 секунды:
    P.S. Я выложил на sqlfiddle версию с группирующей вьюшкой. Львы и львицы, подходящие в равной степени, отскаются на этапе create view — остаются только наименьшие id. Потом по этой выборке делаются запросы в порядке убывания приоритета.
    Случаи пар с разными рейтингами, где один из партнеров повторяется, возможны!
    http://sqlfiddle.com/#!9/4c991/1

    По понятным причинам, миллион записей на sqlfiddle не загонишь. Демо с 500 львами. У меня на миллионной таблице запрос без кеша выполняется за 4 секунды.

    P.P.S. Я не считаю этот вариант правильным и окончательным. Буду благодарен за подсказки.

    P.P.P.S. Chushkin, насколько я вижу, у вас не отбрасываются повторы львов и львиц даже в пределах одного рейтинга. Так что ваш вариант на эталон тоже не тянет.
     
  14. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Эээ, вообще-то "...несколько подходящих в равной степени..." выполняется, в подзапросе с "group by t1.id, rating".

    Добавлено спустя 1 минуту 58 секунд:
    Это сарказм?

    Добавлено спустя 28 минут 14 секунд:
    artoodetoo, сравнил Ваш вариант со своим: на 100% (т.е. у меня rating = 0) совпадает, остальное не совпадает.
    Возможно из-за того, что алгоритмы расчёта "подходящих" разные.
    (кстати, малость поправил мой запрос /сортировку/)
     
  15. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
  16. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Там надо поправить:
    Код (PHP):
    1. order by rating, id2 -> order by rating, id1
     
  17. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Я так понял все забили на это задание.
    Тогда выкладываю свой вариант решения. Должен выбрать 3 пары с рейтингом 0, а все остальные с рейтингом 1.
    Числа взяты не из головы, а продиктованы логикой и здравым смыслом.
    Естественно первые два куска запроса должны выглядеть иначе, но выберут те же самые индексы.
    Код (PHP):
    1. (SELECT *, (abs(s1.wool - s2.wool) + abs(s1.color - s2.color)) as rating 
    2. FROM `lions` as s1 LEFT JOIN `lions` as s2 on (s2.id = (s1.id + 5099))
    3. WHere s1.id = 1)
    4. UNION 
    5. (SELECT *, (abs(s1.wool - s2.wool) + abs(s1.color - s2.color)) as rating  
    6. FROM `lions` as s1 LEFT JOIN `lions` as s2 on (s2.id = (s1.id + 29))
    7. WHere s1.id = 5101 OR s1.id = 5131 OR s1.id = 5161 
    8. OR s1.id = 5191 OR s1.id = 5221 OR s1.id = 5251 
    9. OR s1.id = 5281 OR s1.id = 5311 OR s1.id = 5341 
    10. OR s1.id = 5371 OR s1.id = 5401 OR s1.id = 5431
    11. OR s1.id = 5461 OR s1.id = 5491 OR s1.id = 5521 
    12. OR s1.id = 5551 OR s1.id = 5581 OR s1.id = 5611 
    13. OR s1.id = 5641 OR s1.id = 5671 OR s1.id = 5701 
    14. OR s1.id = 5731 OR s1.id = 5761 OR s1.id = 5791) 
    15. UNION
    16. (SELECT *, (abs(s1.wool - s2.wool) + abs(s1.color - s2.color)) as rating 
    17. FROM `lions` as s1 LEFT JOIN `lions` as s2 on (s1.id = (s2.id + 1))
    18. WHere s2.id = 10000000)
    19. ORDER BY rating LIMIT 0,25
    На самом деле все может быть совсем не так. НО...
    [​IMG]
    Можете удалить, если считаете полной лажей.