Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Тип данных как BIGINT для логических операций, но длиннее
 
 автор: yadyra   (10.03.2012 в 16:19)   письмо автору
 
 

Добрый день. Хочу хранить в одном столбце набор опций (1-присутствует, 0-отсуствует), одна опция - один бит. Соотвественно в условие выборки выглядит как
SELECT ... WHERE options & $options
например, $options = 0xС0 или 11000000 (двоичная), т.е. первые две опции включены. Понятно, что выбираются записи, в которых опции хотя бы в одном бите совпадают с маской $options.
Однако в BIGINT можно хранить 64 бит для логических операций. А какие варианты можно предложить для хранения большего числа, 80 например?

  Ответить  
 
 автор: Valick   (10.03.2012 в 17:25)   письмо автору
 
   для: yadyra   (10.03.2012 в 16:19)
 

на мой взгляд не очень хорошая идея, (тем более что лично у меня не работает, ну может просто ума не хватает)
я бы лучше сделал 80 полей
выборку (а иногда и группировку) легко организовать, что по одному полю, что по всем 80
правда надо на счет нагрузки потестить

  Ответить  
 
 автор: yadyra   (10.03.2012 в 17:36)   письмо автору
 
   для: Valick   (10.03.2012 в 17:25)
 

Идея просто отличная в том плане, что скорость работы зашкаливающая (пробовала с 24 битами). Плюс удобство - что ищем переводим в биты (это делается) как
$rtvs = $raidcall*8+$teamspeak*4+$ventrilo*2+$skype;

(можно и со сдвигом)
а на выходе в скрипте по AND маске получаем "все по отдельности".
Да, только сейчас возник вопрос - может и php не поддерживает более 64 битные переменные, сейчас гляну.
UPD. Поддерживает

  Ответить  
 
 автор: Valick   (10.03.2012 в 17:42)   письмо автору
 
   для: yadyra   (10.03.2012 в 17:36)
 

не могли бы вы кусок кода подкинуть, для потестить
или сюда прикрепить или на почту кинуть
хоту разобраться в этом вопросе
и если в одно поле не лезет, сделайте 2х64 :)

  Ответить  
 
 автор: yadyra   (10.03.2012 в 17:53)   письмо автору
 
   для: Valick   (10.03.2012 в 17:42)
 

function time_track($shour, $ehour) // Преобразует время от $shour до $ehour в последовательность бит
    {
    $time_track = 0xFFFFFF; // FF FF FF
    if ($shour == $ehour) return $time_track;
    if ($shour <= $ehour) {$s=$shour; $e=$ehour;} else {$s=$ehour; $e=$shour;}
    $time_track = $time_track >> (24-$e);
    $time_track = $time_track << (24-$e); // отрезали с конца часы
    $time_track = $time_track << $s;
    $time_track = $time_track & 0xFFFFFF;
    $time_track = $time_track >> $s; // отрезали с начала
    if ($shour > $ehour) $time_track = $time_track ^ 0xFFFFFF; // для случая перехода через 00:00
    return $time_track;
    }

Функция переводит время игры от shour до ehour в 24 бита, 1 - играет, 0 - не играет.
Если делаем запрос SELECT ... WHERE `time_track` & $time_track
то выводит если есть совпадение хоть по одному биту (подробности тут, но там в коде у меня была ошибка).
Сейчас хочу использовать подобное решение для хранения опций, и их уже более 64.

  Ответить  
 
 автор: Valick   (10.03.2012 в 18:03)   письмо автору
 
   для: yadyra   (10.03.2012 в 17:53)
 

спасибо, еще бы кусок дампа таблицы было-бы совсем хорошо

  Ответить  
 
 автор: yadyra   (10.03.2012 в 18:07)   письмо автору
 
   для: Valick   (10.03.2012 в 18:03)
 


function dbconnect(&$db) // соединяемся с БД
    {
    $user = 'root';
    $password = '';
    $table = 'tmp';
    $db = new mysqli('localhost', $user, $password, $table);
    $db->query('SET NAMES \'utf8\'');
    }
dbconnect($db);
    for ($i = 0; $i<10000; $i++)
        {
        $shour = rand(0,23);
        $ehour = rand(0,23);
        $time_track = time_track($shour, $ehour);
        $query = "INSERT INTO `mytime` (`time_track`) VALUES ('$time_track')";
        $db->query($query);
        }

  Ответить  
 
 автор: Valick   (10.03.2012 в 18:13)   письмо автору
 
   для: yadyra   (10.03.2012 в 18:07)
 

время только часы, а то я уже с UNIXTIME экспериментировать начал
запрос по маске должен вернуть тех кто был в игре за промежуток времени, пришедших и сваливших включительно?

  Ответить  
 
 автор: yadyra   (10.03.2012 в 18:44)   письмо автору
 
   для: Valick   (10.03.2012 в 18:13)
 

Время это int. Просто цифра :) Которую мы используем для &, и не более.
Иллюстрация: http://demiart.ru/forum/uploads8/post-714290-1320768544.gif
Да не нужно привязываться к маске и логике. Это рабочая функция, все отлично работает на готовом проекте. Я пытаюсь подобную технику использовать для хранения списка опций уже в другом скрипте.
Просто чтобы 1 & 1 = 1 и все. И чтобы можно было более 64 бит. Если нужны подробности о time_track, то тут она, там вся проблематика.
UPD. Почему лучше не использовать 2x64?
Потому что это нарушит архитектуру. Есть запрос, который извлекает из одной таблицы все опции: их название, а также порядковый номер бита. Потом делаем запрос ко 2 таблице с маской. А если 72 опции, то уже придется кодировать не только номер бита, но и где он хранится.
Ладно, сейчас попробую 2x64

  Ответить  
 
 автор: Valick   (10.03.2012 в 19:44)   письмо автору
 
   для: yadyra   (10.03.2012 в 18:44)
 

Да не нужно привязываться к маске и логике.
как это не надо, очень даже надо, я же должен ведать что творю
ходил по ссылке, принцип понятен, но вот применение в самой игре не понятно
____
хорошо что вы пришли на этот форум, тут такие как вы позарез нужны :)

  Ответить  
 
 автор: yadyra   (10.03.2012 в 20:25)   письмо автору
 
   для: Valick   (10.03.2012 в 19:44)
 

Спасибо за похвалу. О форуме узнала из книги самоучитель MySQL.
Описание скрипта и его работа тут
Простым языком говоря, есть игрок 1, который размещает анкету и указывает время игры, например от 10.00 до 20.00.
Приходит второй игрок, ищет анкеты людей, причем он сам играет с 12.00 до 15.00. Находит анкету первого игрока. То есть время игры должно перекрываться. А бинарное логическое И дает возможность сравнить время, если каждый бит - это время игры. Хоть один бит совпадает - значит время игры совпадает хоть по одному часу. А потом уже в скрипте можно сделать бинарное И, получить результат, и, посчитав количество бит в нем, определить совпадение времени в часах. Можно и в MySQL это сделать, функция bit count (не помню как пишется).
И мне понравилось работать с битами. А массовое хранение опций "есть", "нет" напрашивается именно на такой способ хранения. У мне 72 опции. Наверное, придется реализовывать 2x64 (или даже 4x32), так как php отказывается работать (не правильно работает) с такими числами.
UPD. А если хранить список опций таким способом, то искать стоит так: (`options` XOR $mask) AND $mask.
UPD2. То есть у меня задача такая: есть, скажем, автомастерская 1.
Она указывает
1. чиним двигатель(0 - не чиним)
2. чиним двери (1 - да, чиним)
3. пылесосим салон (1 - да, пылесосим).
В бинарном виде это 011
2 автомастерская: чинят все (111)
Мужик ищет мастерскую, где бы ему починили двери, то есть 010.
Делаем поиск (`options` XOR $mask) AND $mask, если не нуль, получаем что мастерская подходит. Для 010 подходят обе. Для 110 - только вторая "чиним все"

  Ответить  
 
 автор: Valick   (10.03.2012 в 22:25)   письмо автору
 
   для: yadyra   (10.03.2012 в 20:25)
 

теперь гораздо яснее, но есть одно но, в запросе по демо ссылке нет сортировки
без сортировки игра не стоит свеч
по этому полю сортировка нормально проходит?
___
WoW - это круто, у меня жена на офе играет :)

  Ответить  
 
 автор: yadyra   (10.03.2012 в 22:50)   письмо автору
 
   для: Valick   (10.03.2012 в 22:25)
 

Сортировка есть, она сделана на основе релевантности (уже в скрипте). Можно конечно и в запросе такое реализовать, но не хотелось все это закладывать в запрос, слишком замороченный он тогда получится.
У меня там считается пересечение времени, то есть число часов, которые играют оба игрока. По этому полю скрипт рассчивает релевантность, прямо влиящую на сортировку. А также рассчитывается "антивремя", то есть если часы, когда играет один из игроков, но не играет второй. Это также влияет на релевантность (смысл: вывести в первые ряды игроков с максимальным совпадением времени). И прочие параметры - совпадение средств связи учитывается. В описании это сказано.
Таки решена задаче через 4x32. Конечный запрос примерно такой
WHERE ((g.girl_services_0x32 ^ 32) & 32 OR (g.girl_services_0x32 ^ 0) & 0 OR (g.girl_services_0x32 ^ 0) & 0 OR (g.girl_services_0x32 ^ 0) & 0)= 0
32 - (просто совпало с 32, м.б. любым) это параметр "100000" в первом блоке по 32

  Ответить  
 
 автор: Valick   (10.03.2012 в 23:38)   письмо автору
 
   для: yadyra   (10.03.2012 в 22:50)
 

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

  Ответить  
 
 автор: yadyra   (11.03.2012 в 01:08)   письмо автору
 
   для: Valick   (10.03.2012 в 23:38)
 

Там в запросе стоит последние обновленные, LIMIT 30, так что ничего страшного. код в несколько строк. идет банальный подсчет совпадающих бит, вводятся несколько коэфициентов.

for ($i = 0; $i<count($result); $i++)
        {
        // Рассчитываем релевантность
        $bc_time = enum_convert::bit_count($time_track & $result[$i]['time_track']);
        $bc_anti_time = enum_convert::bit_count($anti_time_track & $result[$i]['time_track']);
        $bc_rtvs = enum_convert::bit_count($result[$i]['rtvs'] & $rtvs);
        //$bc_now = bit_count($result[$i]['time_track'] & $now_track);
        $result[$i]['relevancy'] = $bc_time*3 + $bc_rtvs - $bc_anti_time;    
        }
        function compare($x, $y)
            {
            if ($x['relevancy'] == $y['relevancy']) return 0;
            elseif ($x['relevancy'] > $y['relevancy']) return -1;
            else return 1;
            }
        usort($result, 'compare');
        return $result;
}
// вырезано из класса
static function bit_count($v) // Считает количество "1" в 32-разрядной переменной
        {
        $v = ($v & 0x49249249) + (($v >> 1) & 0x49249249) + (($v >> 2) & 0x49249249);
        $v = (($v + ($v >> 3)) & 0x381c0e07) + (($v >> 6) & 0x381c0e07);
        return ($v + ($v >> 9) + ($v >> 18) + ($v >> 27)) & 0x3f;
        }
    }    

  Ответить  
 
 автор: Valick   (11.03.2012 в 07:39)   письмо автору
 
   для: yadyra   (11.03.2012 в 01:08)
 

Там в запросе стоит последние обновленные, LIMIT 30
т.е самые релевантные могут не попасть в выборку, это же не есть хорошо
это расчет только по времени, так что для "полного счастья" код увеличиться раз в пять
опять же при выборке по классам идет четкая зависимость если хотим война, значит воин, но танковать могут и ДК и паладин в зависимости от спека ну и тд.
идея у вас замечательная, я думаю её нужно хорошенько развивать
___
в любом случае спасибо за подробные объяснения

  Ответить  
 
 автор: yadyra   (11.03.2012 в 11:43)   письмо автору
 
   для: Valick   (11.03.2012 в 07:39)
 

>>т.е самые релевантные могут не попасть в выборку, это же не есть хорошо
Пока что так. Кроме того если прикинуть, кто попадет в выборку "самые последние, 30 штук", "сервер", "фракция" (это самый минимум при поиске, даже без времени и связи), то из этих 30 человек многим анкетам будет уже более месяца. Ну а зачем показывать более релевантные "старые анкеты", если их хозяева уже давно может забросили это дело. Так что время последнего обновления влияет на результаты, иначе в топе бы висели те, кто поставил все виды связи, все дни недели и указал самое популярное время игры (10-18 часов, например).
В общем я знаю о проблемах с релевантностью, и еще в этом направлении предстоит много сделать. Сейчас разработка приостановлена, есть вещи поинтересней.
>>идея у вас замечательная, я думаю её нужно хорошенько развивать
Идея не моя, а взята с сайта воврейдер, вроде, я лишь программирую для одного человека который захотел подобное для своего сайта.
>>больше 64 бит в одном поле хранить не выйдет
да тут пришлось с "over 64" перейти на 4 столбца по 32, сказываются ограничения php, уже все сделано и работает :)
Спасибо за дискуссию

  Ответить  
 
 автор: Valick   (11.03.2012 в 14:02)   письмо автору
 
   для: yadyra   (11.03.2012 в 11:43)
 

Кроме того если прикинуть, кто попадет в выборку "самые последние, 30 штук"
это в расчете на небольшое количество людей, представьте если 500 человек обновили свои данные в течение последнего часа, из них в выборку попадут всего 30.
я конечно представляю что на пиратках народу не бывает лишнего, все время дефицит
но логика завязанная на количество сами понимаете :)
но это уже совсем другая история, главное что бы заказчик был доволен ;)
___
еще на демо сайте слайдером можно выбрать время от 0 до 24, а вот 4 часа игры с 23 часов до 03 указать нельзя ;)
еще кроме раидкала и вентрилы есть mumble, правда кроме офа я его ни на одной пиратке не встречал
вы меня извините, я не придираюсь, я "что вижу то пою" :)

  Ответить  
 
 автор: Sfinks   (11.03.2012 в 02:21)   письмо автору
 
   для: Valick   (10.03.2012 в 23:38)
 

Извините, что вмешиваюсь )
Как раз кажется вы у кого-то спрашивали нафига нужен тип SET и куда его можно применить?
Это как раз тот случай. Т.е. тип SET это визуализация побитовых операций. Т.е. данные в этом типе хранятся как ЦЕЛОЕ просто при создании поля каждому биту присваивается как бы имя. И операции с этим полем такие же быстрае как с целым.
_____
P.S. больше 64 бит в одном поле хранить не выйдет. И ЦЕЛОГО больше БИГИНТа нету и СЕТ максимум 64 элемента может иметь.

  Ответить  
 
 автор: Valick   (11.03.2012 в 07:40)   письмо автору
 
   для: Sfinks   (11.03.2012 в 02:21)
 

при таком раскладе один из нас не понимает назначение поля SET :)
будет время займусь этим вопросом

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования