Pull to refresh

Comments 95

Первый пример просто убил. Сразу видно: автор долго сидел над оптимизацией
А мне, представьте, пришлось менять разбросанные от 1 до 10 000 000 айдишки на упорядоченные в основной и связанных таблицах (благо, структура ДБ не блистает оригинальностью).
Я, конечно, представлял, что новички могут ошибаться… Но чтобы рабочий проект, да так…
Однако неплохая база, в которой 10 000 000 записей, значит и проект не просто хомяк :)
Уверен, тяжело вам пришлось!
Записей в основной таблице около 80 тыс., до 10 млн. были разбросаны их айдишки (благодаря рандому). Проект — далеко не хомяк. =)
Я все еще офигеваю: это ж догадаться еще надо таким образом генерировать! А если бы числа псевдослучайные генерировались? )))
А они имхо такие и есть :)
а гуиды в mssql видели?))
тут недавно про BITRIX проходил пост…
Нет, а теперь мы представим, что произошла одна из ошибок базы данных и кроется while(...mysql_error()) медным тазиком, пока база не очнется или лимит времени выполнения не иссякнет :/
И не дай боже foreign keys (me вздрагивает)
Вполне себе адекватный код. Возможно, поолезно, когда злоумышленник можетчто-то сделать при добавлении в базу, зная id который получится. Или, например, чтобы максимальный id реально не соответствовал количству чего-то(например, вы не хотите показывать количество сообщений на форуме, однако, запостив одно сообщение, злоумышленник сможет приблизительно узнать их количество)
Тем боле, из кода не ясно, что id это message_real_id а не message_fake_id, например.
Опасный тип этот злоумышленник — знает количество сообщений на форуме! =)
(кстати, на вышеупомянутом сайте было написано сколько элементов в этой таблице).

Если кто-то может что-то нехорошее сделать зная id, то нужно удалить весь код и писать заново.
Я имел ввиду что он сможет сделать что-то нехорошее не с сайтом.
И я об этом: если кто-то может испортить ваш сайт (DDoS не в счет), то нужно избавиться или от злоумышленника, или от сайта! =)
Это адекватный код? Генерировать десяток, а то и сотню ошибок базы на ровном месте… это как-то очень неадекватно. А в тех случаях, когда не нужно, чтобы пользователи знали количество, делается просто дополнительный столбец id, выборка по которому идет на сайте. К PK это иметь отношение не должно. Такое бывает, например, с количеством интернет-заказов в магазине.
кто мешает сделать нормальный id по auto_increment и второе поле с id или словами или даже с хэшами, которые будут видеть пользователи?
Это называется security through obscurity и является абсолютным бредом.
мне это показалось банальной диверсией
Интересно еще, что в случае достаточно старой версии PHP (до 4.2.0) и забытого srand() в первом примере каждый раз одна и та же цепочка «случайных» чисел будет генерироваться.
А в новом думаете не будет? mt_rand должен дать немного больше чисел в последовательности, но в любом случае БД может хранить больше :)
Пожалуй смешнее всего будет, если это запустят под Windows, где очень маленькая длинна последовательности.
Не будет. srand() и mt_srand() делаются автоматически с 4.2.0.
mt_rand в состоянии давать равномерно распределенные псевдо-случайные числа от 1 до 231 — 1, период у нее вообще огромен, короче, для целей генерации уникального INT id более чем подходит.
Да, я как раз прочитал про это. Но говорил я о другом, в исходном коде упоминается именно rand(), у которого диапазон меньше.
Тут дело не в качестве псевдослучайной последовательности. Просто если цепочка будет повторятся каждый раз, то этот кусок кода будет проверять сначала все числа, которые уже содержаться в БД, и только после этого находить псевдослучайное число, отсутствующие в БД. Соответственно если мы добавим 100000-ную запись в БД, то и цикл поиска свободного id тоже прокрутиться 100000 раз, и столько же будет попыток INSERT'а.
Согласен. Не знал про это различие с автоматическим вызовом в «старом»/«новом» PHP.
ну я буквально вчера вычислял число по модулю воттак: y=x*((x>0)-0,5)*2 эта привычка(логику в вычисления писать) еще со времен спектрума меня по сей день преследует.

Иногда такие размашистые формулы получались :)
Вам сам Бог велел на Брейнфаке писать! =)
>С математической точки зрения, условие «sqrt(x) = x/sqrt(x)» выполняется всегда,
Ой, случайно отправил.
>С математической точки зрения, условие «sqrt(x) = x/sqrt(x)» выполняется всегда.
Я зануда — при x=0 не выполняется.
А, вы про пределы? Бррр… Не напоминайте! =)
он по моему про деление на ноль :)
На ноль только на компутере делить нельзя. =)
в математике тоже нельзя (не путать с бесконечно малыми функциями)
Ладно, вы победили, сейчас исправлю. =)
sqrt(-1) = i
i= -1/i
Это если с математической точки зрения.
На компе такое, если это не специальный пакет, скорее всего не выполнится.

В копилку:
if 1 == 2: # блин, этот участок кода никогда не выполняется :(
Причина: 1 не равен 2-м
Совет: используйте «if 1 == 1: ...»
образование ника здесь немного по другому принципу шло
Вот вы тут шутки шутите, а люди не то что мои примеры оправдывают, но и ваш вариант нормальным кодом называют…
Да это просто такой способ закомментировать кусок кода. Не знаю, почему его используют, но я частенько встречал такое.
Могу предположить, что там изначально стояло другое, осмысленное условие, но в процессе отладки оно многократно менялось, и/или автор не захотел вымарывать большой кусок кода полностью, а закомментировать было лень, и/или в этом блоке используется альтернативный вариант алгоритма или неиспользуемая на данный момент недописанная функциональность и автор хотел сохранить его на будущее (а если закомментируешь, то другой программист или даже сам можешь случайно стереть закомментированный код, как ненужный), вот и оставил такое.
После рефакторинга, скорее всего, этот кусок был бы удалён, но когда проект уже работает, может быть не до рефакторинга — работает, значнит ничего не трогай :)

Сам я часто использовал такой кусок:
a = 1
if a == 2 call somefunction
и т.д.
чтобы иметь возможность в режиме отладки вызвать какую-нибудь функцию, которая в нормальном режиме работы программы не нужна.например, просмотреть статус какого-нибудь объекта, записать что-нибудь в лог и т.п.
потому что изменить значение переменной «а» в отладчике легко, а вот вызвать какую-нибудь произвольную функцию скорей всего невозможно (в firebug возможно всё, потому я больше не пользуюсь таким приёмом :)
меня спасает добавочная "|| 0" ;-)
Хм, а мне приходится писать "&& 0". В всех языках, которые мне известны (видимо, их не слишком много), x || 0 == x.
Ну, в Си очень удачно можно пользоваться макросами для получения «кроссплатформенного» кода.

#ifdef SOME_FLAG

#else

#endif

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

#ifdef SOME_FLAG

#else

#endif
Мне уже интересно! =)
Такое комментирование встречается (правда, в форме #if 0) в случае, когда внутри фрагмента уже есть нормальные языковые комментарии и обернуть их стандартно уже нельзя.

Некоторые редакторы, кстати, помечают блок между #if 0 и #endif как комментарий.
В существование первого примера просто не верится. Это уже не кодобред, а КодоПЦ какой то… что ж у него там будет когда 10 млн достаточно плотно наполнятся, ужос…
Чесное слово, так и было! Я бы сам не поверил, наверное.
Как уже писали выше, сам подход вставления рандомного id может быть оправдан (у самого возникала иногда потребность).
Код же как он написан, является бомбой замедленного действия, как потому, что будет прогрессирующий апокалипсис при количестве записей, приближающемся к 10 млн, так и потому, что забивается на то, почему собственно был mysql_error() — может база отключилась.
Из любопытности, в каком случае случайный идентификатор может быть оправдан?
Ну, например, чтобы скрыть (или сделать менее предсказуемыми) связи в системе.
У Дурова id в контакте 1, сразу интересно, у кого 2, 3 и т.д., т.е. можно делать какие-то выводы о том, как стартовал проект, о личных связях г-на Дурова, например.
В конце концов, это доп. звено в цепи security through obscurity: если злоумышленник не может предсказать идентификаторы внутри вашей системы, ломать ему будет сложней.
Мне кажется для таких целей проще сделать еще одно поле в таблице, куда писать уникальную строку (UNIQUE).
Использование же праймари ключ таким образом…

Я наверное сегодня ночью не усну, после увиденого кода…
Непонятно, почему проще. Ваша строка просто будет вторым праймари ключом, который точно так же надо будет заполнять уникальными значениями.
Проще в том плане, что в этой строке вы сможете использовать не только цифры, но и буквы, и к примеру работать уже с 16-тиричными числами (правда что-то я не припомню генератора случайных HEX чисел), а это означает, что сгенерировать такое же число которое есть становится в разы тяжелей. Это только одна из причин.
Неубедительно. Вам мало INT — возьмите BIGINT и приведите пример сколько-нибудь распространенных реальных задач, где его ну никак не хватит.
По поводу разов — небо упадет на землю, если будет у вас вероятность коллизии 10-5, а не 10-20?
Как вариант — табличка сообщений в базе для JMS. сообщений может вставляться в табличку сотни в секунду, но время жизни у них короткое.
Ох… Даже продолжать не хочется. Тема древна, как Мир. Программирования, понятно. Где-то слышал — программирование, как культура.
Что же делать — давайте двигаться к этой культуре.
Кстати, по первой незадаче — можно же max(id)+1. Если в транзакции.
Ну транзакции-то они вроде не существуют в MySQL?
Почему? InnoDB пока никто не отменял…
Упс, тогда прошу прощения.
Но я очень сомневаюсь, что человек не знающий про auto_increment, знает о существовании InnoDB и уж тем более транзакций.
Да существуют они там давно. Вот только вложенных транзакций вроде еще нет. Далековато в этом смысле еще до Оракла.
… несмотря на то что InnoDB это как раз оракловый движок в девичестве
По первой задаче лучше все-таки чтобы поле id было auto_increment и тогда так:

INSERT INTO `table` SET login='my_login' AND ...

SELECT LAST_INSERT_ID()
Ну очень интересно от кого и за что минус :)

ну вы приходите на форум филологов и начните там рассказыва про словарь Даля…
max(id)+1 — это лишний поиск в индексе…
Исправьте операцию присваивания на сравнение, во втором примере:
if sqrt(x) = x/sqrt(x)
Паскаль, друг мой, паскаль! =)
Упс, по-диагонали прочитал как псевдо-код… Сорри :)
Паскаль не позволил бы вам выстрелить себе в ногу перенести сегмент стека :)

Хочется верить, что на ассемблере пишут только профессионалы. Страшно представить, что бы творилось, будь он проще для освоения/популярнее.
Ассемблер позволяет — сам пробовал =)
хорошенькая книжечка таится под перечеркиванием ,.)
Видимо при написании ассемблерного кода человек не знал, что ss это не регистр общего назначения, и дергать его без особой надобности не стоит.
«Код никогда и никем не был написан».
Идею мне подсказал коллега (сами потом долго смеялись), а «код» написал я, специально для статьи.
Насчет первого примера я сам видел кусок типа crc32(microtime()) и обрезанием -. Очень замечательный код, который на 100000 запросах уже давал 5% повторных ид.
Зеленый еще программист был! Опытный бы сделал md5 и напихал бы в параметры всякого мусора кроме microtime() :)
Во всех случаях заказчики просили скрыть или заменить id,
вопервых потому что слишком маленький или по другой причине.
Нельзя брать кусок кода и сразу делать выводы.
К моменту разработки такое решение могло оказаться максимально приемлемым!
А тут пытаются…
Корме того есть понятие application lifetime по истечении которого надо делать
refactoring.
Что Вы судя по всему успешно и сделали.
Ну а как же классика?
Проверка на true:

bool value;

if (value.ToString().Length == 4)
{

}
да, машинная точность это тема. Попробуйте например в питоне вот это:
0.3==1-0.7
Что вы хотели, 0.29999999999999999 != 0.30000000000000004
> Совет. Понять свой код. Убедиться в том, что в программе протекают задуманные процессы.
Совет. Чтобы понять свой код нужно написать тест к этому коду.
UFO just landed and posted this here
Есть у меня один приятель. Писал он логгер для одной большой системы, который скидывал различные записи в файл.
так вот алгоритм открытия файла у него выглядел следующим образом:

// Псевдокод:

while(!file.Open())
{
// Подождем еще немножко
thread.Sleep(1000);
}

P.S. Комментарий в коде выглядел именно так, как привел его я :)
Потом число можно заменить на 500 и заявить о двукратном увеличении скорости.
> upd: Ввиду появления большого количества защитников «случайных» идентификаторов в таблицах БД,
> отвечу всем сразу: если необходимо скрыть реальные ID, нужно использовать mod_rewrite, а не коверкать БД.

В данном случае можно задействовать линейное преобразование:

externalID = ((internalID + Q1) * Q2) mod Q3

Q2 и Q3 должны быть взаимно простыми, тогда соответствие гарантированно будет однозначным. Максимальное количество пользователей будет равно Q3 (internalID от 0 до Q3-1).

internalID может быть auto_increment, а externalID вычислимым полем (вроде, поддерживаются они в MySQL?)

Ну а в MS SQL можно использовать uniqueidentifier (GUID).
Ввиду появления большого количества защитников «случайных» идентификаторов в таблицах БД, отвечу всем сразу: если необходимо скрыть реальные ID, нужно использовать mod_rewrite, а не коверкать БД.

А тормоза учитывали? — тут вам не простой регэксп написать. А если не апач и вообще не веб?
Я и сам могу выдумать много способов, как скрыть реальные ID, и мне даже больше о душе «не коверкать БД», но дело-то не в этом. Дело в том, что «защитники», в частности, я, утверждают, что такой подход имеет смысл и право на существование, вы же упорно списываете его в кодобред.
К слову о #define true false

karbas@arc|~$ python --version
Python 2.5.1
karbas@arc|~$ python -c 'print 1==1
True = False
print True'
True
False

еще о #define true false — в Javascript волшебные последствия может иметь строчка наподобие
undefined = true;.
Нет гарантий, что некий не слишком эрудированный кодер не выберет для своей переменной такое говорящее имя, а последовать могут всякие странности типа обращений к несуществующим полям и объектам там, где всё, казалось бы, проверяется, в чужих, сторонних, «взрослых» библиотеках. Кстати, и защита от этой пакости тоже есть: если ваша библиотека изолирована в функцию (так обычно делают всякие «приватные» поля и методы, см. классиков), можно объявить в ней var undefined; и жить спокойно.
Sign up to leave a comment.

Articles