Pull to refresh

Comments 230

Перечисления

У enum 2 проблемы:
  • нестандарт (исторически)
  • неудобно модифицировать код/структуру, т.к. привязка к datasource
Вот вот. База данных – это слой хранения данных. Он должен отвечать за их сохранность и целостность, но не за валидность.

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

кроме того есть такие вещи как FoxPro, MS Access, где собственно и логика вшита в СУБД.
Разве миграции не решают проблему с обновлением в ENUM?
А как они её решают? Все равно в миграции вы делаете alter table.

Нц короче я, например, забыл про Enum при работе с Rails. Да я и про MySQL почти забыл…
DATE, TIME, DATETIME vs TIMESTAMP это дикий холивар, в нете найдете много материала почему лучше НЕ TIMESTAMP :)
лично для себя решил так:

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

DATETIME лучше подходит для каких-то исторических событий, например дня рождения, т.к. он всегда в один и тот же день, не зависимо от часового пояса.

по-этому для указания даты новости, например, я использую TIMESTAMP, а для указания ДР при регистрации пользователей — DATE
а я для себя решил — TIMESTAMP сугубо когда нужно считать разницы между строками потом (т.е. почти никогда :))) все остальное DATE|TIME
Простите, а как вы выводите тогда дату и время какого нибудь события для людей из разных часовых поясов?
именно в такой постановке вопроса — например CONVERT_TZ() но вообще все даты обычно выводятся в каком-то одном поясе и его нужно просто установить
То есть вы каждый раз в каждом запросе переводите дату и время из временной зоны сервера во временную зону пользователя?

Это лучше чем вариант с хранением даты в TIMESTAMP и одном дополнительном запросе (set @@session.time_zone = '+03:00';) на сессию?
Перечислите пожалуйста несколько, кроме того, что данные хранятся в UTC.
Единственный минус, который увидел для себя — ограничение по дате 2038 годом. Зато занимает 4 байта вместо 8 и выборки по ним происходят быстрей (экономия на спичках, но все же).
вы удивитесь но выборки с date быстрее чем timestamp причем прилично (http://gpshumano.blogs.dri.pt/2009/07/06/mysql-datetime-vs-timestamp-vs-int-performance-and-benchmarking-with-myisam/) — дело в отстутствии конвертации с понятного нам языка в инт.
самое главное различие — 99% ф-й работает именно с датами а не таймстемпами => не нужна конвертация = чище запросы, выше скорость
Да, согласен. Ведь получается что все дерево индекса проходит дополнительную обработку.
Но в случае когда поле просто участвует в селекте, вида SELECT time FROM tbl WHERE category_id = 123 выборка будет быстрее, т.к. таблица меньшего размера = меньше IO и преобразования необходимы только для выбранных строк, а не всего индекса.
Опять же, случаи бывают разные. Но все равно спасибо :)
в базах бывают ещё и вьюхи, вы этот момент полностью пролюбили в своей шпаргалке
А еще и хранимые процедуры, функции и триггеры до кучи, которые просто так не дампятся (хотя триггеры по дефолту и дампятся).

Для полного дампа (вместе с хранимыми процедурами/функциями) mysqldump'у надо явно указать опцию --routines
Сегодня столкнулся с тем, что если view построена по таблицам или полям, которых уже нет в базе, то mysqldump отваливается, нужно указать опцию --force. Очень неожиданно.
ну вьюхи в mysql это как-то противоестественно, извините
Они плохие.
И чуть что, ведут к усиленному использованию временных таблиц
можно почитать про довольно общие случаи обязывающие к использованию алгоритма TEMPTABLE
dev.mysql.com/doc/refman/5.1/en/view-algorithms.html
Мерси за разъяснение.
Кстати, кто мне может указать на смысл использования вьюх в БД? Ведь падение перфоманса, по-моему, перекрывает ихние выгоды.
это и стандартизация интерфейс и иногда кэширование.
Секьюрити, индексированные представления, вертикально разделенные (архив + актуальное из разных таблиц) и т.д.

Зря Вы на них так категорично (-:
>> Помните, что тип TEXT ограничен только 64 килобитами, поэтому что бы сохранять «Войну и Мир» пользуйтесь «LONGTEXT»
А фильмы как хранить? )))
>> Самая правильная кодировка для вашей БД UTF8
Ох тут щас начнется.
Ох тут щас начнется.
сторонники cp1251? да ну их нафиг, потом занимайся перекодировкой, когда данные приходят с сервисовм в нормальном utf/
сторонники не utf-8 уже вымерли, или должны были по крайней мере
В том, что 99% проектов Рунета никогда не посетит человек из Китая.
При таком раскладе, чего мелочиться — даёшь koi8-r/u :)
Зачем перегибать и доводить до абсурда?
вот и вам про то же говорят %)
99% проектов — это перегиб? Ну-ну.
Каких символов в UTF-8, по-вашему, не хватает для рунета в cp1251?

У Мэйл.Ру одно из самых больших хранилищ в Восточной Европе.
Было бы самым большим, если б везде использовали UTF, ага =)
Если 99% процентов проектов Рунета по вашей версии рассчитаны исключительно на пользователей русской версии Windows, почему мне периодически приходят просьбы прочитать письма с яндекса и всяких одноклассников от близких мне людей, живущих далеко на запад?
Наверное, Вы тоже нерепрезентативны. Как-то так.

Кстати, Яндекс и Одноклассники юзают UTF, насколько мне известно.
Но именно по той причине, что они относятся к тому самому одному проценту проектов.
Они как раз пользуют koi8 для мыла.
Не, у Яндекса всё умнее.
Они по возможности используют КОИ (и это в большинстве случаев оправдано, хотя не очень понятно почему кои, а не цп1251), но если в письме встречаются символы, которых в КОИ нет, отправляют письма в UTF.

Насчет одноклассников не уверен, проверить не могу.
Именно по этой причине, я с яндекса сестре пишу транслитом, а не русским языком, иначе я в ответ получаю «WTF».
А вам никогда не хотелось проверить почту или почитать новости или хабр или бложки находясь за границей в публичной интернетной?
Никогда, у меня для поездок ноут, но в этом плане я нерепрезентативен, признаюсь.

Возможно, мою цитату не очень поняли.

Я имел ввиду, что проекты Рунета в большинстве своем рассчитаны на русскоговорящее население, а не на носителей китайского языка, например. Поэтому в большинстве случаев вполне хватит cp1251. Естественно, если у проекта есть значительная иноязычная аудитория, в текстах для которой используется большое количество символов не из cp1251, то UTF будет рулить. Но на практике дефолтное использование этой кодировки — тоже самое, что пытаться сразу использовать Oracle для домашней гостевой книги.
Вариант когда у пользователя в системе попросту нет cp1251, вы не рассматриваете по определению?
Да и подход «раз мне не надо, то и остальным тоже» весьма практичен.
Начните для начала разделять тех, у кого «нет cp1251», от тех, кто «находится зарубежом и не смог ее включить». 95% аудитории Рунета сидит на Винде, с чего бы у них не было 1251?
Вы хоть понимаете о чём я говорю?
Если у пользователя windows не русифицированный (а таких полно среди наших за рубежом), то кодировки у него стоят совершенно другие.
Это вы да я знаю что такое cp1251 и как его получить, а им до этого как нам до луны пешочком.
А Вы хоть понимаете, что основная зарубежная русскоязычная аудитория будет как раз у того 1% процента проектов, для которых использование UTF не только желательно, но и обязательно?

Смотрите, в рунете порядка нескольких миллионов доменов, процент от них — десятки тысяч. В эти тысячи вполне попадает большинство соц.сетей, больших форумов, новостных ресурсов, почтовых служб и инстант-мессенджеров. Выкиньте их, и увидите, что зарубежная аудитория оставшихся не такая и большая, чтобы задумываться.
Меня огорчает, что я не могу с крупного сайта с большущей аудиторией отправить письмо на родном языке близким людям за рубеж, хотя с sms такого вопроса даже не возникает.

Меня огорчает, что люди не могут прочитать email c крупной соцсети, у которой приличное кол-во зарубежных пользователей.

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

Разумеется, можно забить на таких пользователей, но ведь можно и сделать их чуточку счастливее.
А вы не думали о том, что русскоязычным людям требуется использовать китайский, японский, финский, чешский итд языки?
В Рунете? Я по-моему, только про Рунет писал.
И я про рунет. Я знаю тысячи сайтов где без utf-8 ну никак…

из известных, тот же rutracker.org где пишут оригинальные названия чего-либо.

А так же, да, не стоит забывать про пользователей рунета не из России.
Причем они могут быть даже не русскими.
Вы удивитесь, но писать оригинальные названия можно без UTF.
HTML-entities это вполне позволяют, причем прозрачно (!) для пользователя. То есть, можно писать хоть на иврите, хоть на катакане, браузер сам отправит нужные entities на сервер.

А теперь попробуйте прикинуть какой объем текста на рутрекере пишется латинскими и русскими буквами, а какой — на иврите, катакане и прочих языках, символов которых нет в cp1251. И получите, что ради 0.001% текстов вы раздуваете хранилище, излишне напрягаете процессор, гоняете больше данных по сети.

Впрочем, опять же — я не призываю отказаться от utf-8.
Я призываю с головой подходить к проектированию систем и использовать то, что требуется, там, где это действительно необходимо, и тогда, когда это нужно, а не только потому, что «все так делают».

P.S. А еще этот комментарий нужен тем (не текст, а наличие комментария), кто лепит минусы тем, чье мнение отличается от их. Лепите, лепите, коль иного мнения вы не приемлите, а все другие мои комментарии в этом топике уже заминусовали. Как дети, ей богу.
UFO just landed and posted this here
Ну. А как следствие размеры индексов, объем потребляемой памяти, размеры бекапов и т.д — все сокращается.

Я экономлю ресурсы (винт, память, процессор, сеть) там, где это возможно, да.
Это плохо?
Несколько странно — кажется, Вы почему-то считаете, что utf-8 чем-то сложнее использовать, чем windows-1251. По-моему — напротив — когда всё везде уже давно работает в utf-8, переключаться в windows-1251, вспоминать, что такое перекодировщик, огребать проблемы с входящими GET-запросами и весь остальной букет — это само по себе сложнее.
попробуй такое:
create table v1 (v varchar(500) primary key) engine=innodb default charset=utf8;
create table v2 (v varchar(500) primary key) engine=innodb default charset=cp1251;
и подумай, что сложнее и почему.
Я сделаю CREATE TABLE без указания CHARACTER SET и оно создаст таблицу в том character set, который у базы данных. Это для _меня_, как программиста в любом случае будет проще.

Если Вы усиленно намекаете на проблемы с производительностью, был бы рад, если бы Вы привели какие-нибудь объективные факты. Если Вы думаете, что в windows-1251 нет collation или он там как-то радикально более быстрый, чем в utf-8 — то, боюсь, Вы ошибаетесь.
Я тут указал character set специально для простоты повторения этого примера. Можете попробовать тот же тест в двух разных базах в разной кодировке. Не принципиально.

То есть самого проиллюстрированного факта, что utf8 требует в 3 раза больше объема памяти для тех же операций с текстом уже недостаточно?
Это зависит от характера текста, а не в 3-а раза больше памяти для любого текста.
Но mysql ведь не знает о характере текста и выделит память с запасом. Или не даст создать индекс, как в примере.
К хранению на диске это не относится, конечно. Для текста можно считать, что объем увеличится процентов примерно на 50%.

А mysql 5.5 уже и 4 байта может выделить для кодировки utf8mb4. Вы за это боролись?
Я ни за что не боролся, просто указал на факт того, что «utf8 требует в 3 раза больше объема памяти» не совсем и не всегда соответствует истине.
Для фильмов есть ФС, нечего всё в базу пихать.
И я про то же. Какой дурак будет «Войну и мир» в бд пихать?
Большие тексты в БД — это нормальное явление
Обычная статья с разметкой может влезать в больше чем 64к.

Да, тут уже привет TinyMCE и подобным Wysiwyg с ихними движками разметки, вставляющими куски лишнего кода не хуже, чем, например, тот же Dreamweaver в режиме визуального создания веб-страницы (думаю, все с него начинали).
Это еще цветочки, вот у кого надо учится, так это у Создателей Ворда!
Unsigned в первую очередь используется для отсекание отрицательных чисел
Да, но можно напороться на грабли, когда переходя через 0 в зону отрицательных чисел получаем MAX_INT
А что Хабраюзеры думают по поводу следующего сервиса (http://www.zoho.com/creator/videos/videos.html) и развития онлайн баз данных?
Нет причин доверять самое сокровенное чужим серверам. Плюс время загрузки страницы увеличивается, так как БД находится чёрт знает где.
может и не самая полная шпора, но несомненно — полезная.
спасибо.
добавьте как делать/заливать сжатые дампы

mysqldump {mysqldump options} | gzip > outputfile.sql.gz
gunzip < outputfile.sql.gz | mysql {mysql options}
Спасибо, добавил к шпаргалке
Добавьте еще про сброс и смену пароля от рута.
Ну и заодно про pv, чтобы можно было видеть успехи процесса. А то, знаете ли, скучно наблюдать за натягиванием 4-гигового дампа :)
zcat outputfile.sql.gz | mysql {mysql options}
Начиная с версии 5.0.3 длина VARCHAR может быть до 65535.
Спасибо, действительно… Сейчас обновлю.
##Количество перечислений ~ 65 тысяч
Гипотетически:
Таблица 1- someID | name
Вот эти name иногда дублируются(ибо им нужны другие ID). Получу ли я прирост в скорости, используя enum на 4,6,9 тысячах элементов списка при выборках?
Спасибо, но это тесты января 2008 года. Всё-таки много времени прошло.
> VARCHAR ограничена 255

По крайней мере в InnoDB влезет ГОРАЗДО больше… примерно 21844 если utf-8
> если вы не знаете что делайте
UFO just landed and posted this here
Терпеть не могу innodb

Да, да, да. А также транзакции, блокировку по строкам, внешние ключи и многое другое.
Да?

Новичков на более чем средних нагрузках ждут сюрпризы.

Еще большие сюрпризы ждут при средних нагрузках на MyISAM.
UFO just landed and posted this here
InnoDB надёжнее, чем MyISAM похвастаться никак не может.
UFO just landed and posted this here
MyISAM имеет существенный недостаток, а именно блокировка всей таблицы:
— Если таблица «почти» рид-онли, то преимущество на стороне MyISAM, но если в таблицу по несколько десятков запросов на чтение и запись, то производительность очень существенно ухудшится.
— При множественных апдейтах больших таблиц, InnoDB может выигрывать порядок-другой при использовании транзакций.
— …

Вывод: лучше всего знать все плюсы/минусы различных типов таблиц и использовать их по назначению, тогда можно добиться максимальной производительности базы.
Это лечится, основной затык ИнноДБ — это быстрорастущий со временем файл базы, ибо по умолчанию он создает все таблицы и базы в одном файле, что для больших баз плохо.
Расскажите это ребятам из Оракла.
Они, видимо, не знают =)
AFAIK, ребята из Оракла в последних билдах как раз и ставят опцию «всё в одном файлу» выключенной ;-)
Выключают-то выключают, но не потому, что плохо, а потому что «The system default is to create a smallfile tablespace, which is the traditional type of Oracle tablespace». Ну и поясняют когда лучше использовать обычные датафайлы (впрочем, максимальный размер последних может тоже кому-то показаться большим), а когда — bigfile tablespaces
Согласен что момент спорный, но моя практика показывает, что после активного добавления/удаления таблиц в режиме «один файл» и добавления/удаления из существующих произвидительность серьёзно снижается, даже после ALTER TABLE… В основном за счет фрагментации (других причин не вижу), в случае отдельных файлов такой проблемы нету.
Дык это, опять же, характерно и для Оракла — если много удалять/вставлять в таблицу (например, используя её для организации очереди), то со временем даже SELECT * FROM tbl WHERE rownum < 100 будет тормозить, пока не сделаешь analize. Именно по причине фрагментации.
С Ораклом работать не довелось, а вот горький опыт на ИнноДБ есть. Особенно печален тот факт что для перевода БД из режима «один файл» в режим «много файлов» помимо переключения настройки, нужно делать полный дамп базы дропать её, и восстанавливать из бекапа, что сделать на живом сервере весьма проблематично ибо базы данных нельзя переименовывать :(
По-моему, такое только для ситуации, когда надо уменьшить место, а не увеличить. Не?
Что-то такое помнится встречалось в документации к работе с InnoDB.
Для уменьшения места, надо убить все таблицы InnoDB из всех баз и файл idbdata*, после чего заимпортить их снова. А для разбиения одной базы на несколько файлов (со сменой режима) достаточно убить только выбранную базу, AFAIK.
Это частный случай из Вашей жизни. Я могу привести обратные случаи из своей.
Вот к примеру, 16-гиговые 4-ядерные сервера тянут у меня 30 тысяч запросов в секунду и не жужжат. Думается, эта цифра — сильно выше «средних нагрузок». О чем говорит пример? Да ни о чем: не зная характера запросов Вы не сможете оценить много это или мало.

А что насчет транзакций, блокировки по строкам и внешних ключей? Ответите?
UFO just landed and posted this here
Про 2 — может автокоммит не был включен?
UFO just landed and posted this here
Даже без коммита запись будет выбираться, ибо место под неё резервируется (равно как и ID), а при откате помечается как удаленная (упрощенно).
А в параллельной транзакции?
Подозреваю, что у автора коммента был именно такой случай.
2. Из пхп: делаю INSERT, беру ID, делаю SELECT по ID. Пусто! А ID вернул. Правда опять же не всегда и не со всеми.

Вероятно всё же INSERT IGNORE, ибо обычной инсерт должен делать сразу SELECT по ID.
Треды виснут по неизвестной причине.

ага, в MyISAM по известной — какой-нибудь запрос на изменение залочил все селекты, и понеслась по кочкам…

Из пхп: делаю INSERT, беру ID, делаю SELECT по ID. Пусто!

Советую почитать про уровни изоляции транзакций. Описанная ситуация крайне вероятна при использовании дефолтного уровня и отключении автокоммита. Вряд ли Вы мне докажете, что такая ситуация была в рамках одной транзакции.

Я от такой квантовой неопределенности инны чес говоря офигел

Это не квантовая неопределенность, а недостаточность знаний о версионных движках вообще и о работе InnoDB в частности. Но это же не проблемы InnoDB, да?
Вряд ли Вы мне докажете, что такая ситуация была в рамках одной транзакции.
Не получится доказать, ибо данные вставляются и размер таблицы растет и ID уже не вернуть. Но у транзакций есть также весомый минус — после откатов таблица становится фрагментированной и необходимо её перестраивать, что на больших таблицах крайне долгая операция и делается посредством темповой таблицы.
Так выпьем же за то, чтобы наши commit'ы были частыми, rollback'и — редкими!
(А откаты — частыми и большими, гы-гы).

Ну да, проблема с фрагментацией будет. А почему у MyISAM ее не может быть? =)
MyISAM фрагментируется в основном от DELETE и изредка после UPDATE; MyISAM можно дефрагментировать командой OPTIMIZE, которая работает быстрее чем ALTER TABLE `name` ENGINE = InnoDB;
Какбэ объяснимо почему поправить таблицу указателей на записи фиксированной длины (если нет Varchar) сильно быстрее, чем копирование данных в новое место. Эт также как любимый аргумент myISAM'щиков, что count(*) работает быстрее, чем в InnoDB.

В целом, конечно, холиварить о сферическом движке в вакууме можно долго.
Главное, чтоб потом при проектировании включали голову.
Я и не холиварю, я стараюсь использовать оба типа таблиц.
MyISAM хорошо подходит для материализованных представлений, которые обновляются раз в n-ное количество минут/часов/дней.
InnoDB отлично подходит для таблиц с конкурирующими чтением/записью, а также там где нужна надёжность и удобство поддержания целостности (то есть почти везде).

P.S. COUNT(*) не намного меньшее зло чем SELECT *. COUNT надо делать по используемому оптимизатором ключу (полю находящимся в этом ключе на первом месте, если ключ составной).
UFO just landed and posted this here
Дык вернуть могло в рамках той сессии, которая сделала вставку.
Но если стоит уровень изоляции REPEATABLE READ и параллельная сессия не делала commit (даже если исходная закоммитила данные), то она не увидит вставки.

Не видя конректного скрипта, мне сложно точно сказать, что же там было, но описанный мной сценарий весьма вероятен, можете попробовать в двух параллельных сессиях к базе его воспроизвести при отключенном автокоммите. Потом попробуйте поменять уровень изоляции на READ COMMITED и снова повторить действия (insert + commit). Будет разница даже, казалось бы, на одном движке.
UFO just landed and posted this here
хм… mysql_* навевает на грустные мысли… А как же PDO и MySQLi?
UFO just landed and posted this here
Про класс никто ничего и не говорил, расширение mysql достаточно старое и не тысячу лет не обновлялось, о транзакциях, как и о много другом, оно даже не догадывается.

P.S. Из мануала:
If you are using MySQL versions 4.1.3 or later it is strongly recommended that you use the mysqli extension instead.
.
Сколько лет версии PHP 4.1.3 можно посчитать самому.
UFO just landed and posted this here
В целом, Вам ответили — хэ его зэ как будет себя вести клиент, не поддерживающий полноценную работу с транзакциями, в среде с кучей параллельных этих самых штук. Да еще с разными уровнями изоляции, откатами, коммитами итп. Но эт точно не проблема InnoDB
Спасибо, добавлю ваши советы.

Я говорил о устаревшем расширении.
а что не так с php_mysql?
UFO just landed and posted this here
Вот тут сравнение движков для mysql в php
uk3.php.net/manual/en/mysqli.overview.php

Но если вкратце, то:
— Объектно ориентированный подход
— Поддержка «prepare statement»
— Поддержка «multiple statement»
— Поддержка транзакций
— Расширенные возможности отладки
Вот мой вариант, того, что действительно полезно:
1) Если делаем mysqldump то на все время пока будет проходить дамп, у нас залочится запись в таблицы. При больших объемах гораздо правильнее снимать дампы со slave или использвать lvm снапшот.
2) Чтобы правильно получить год и неделю, надо групировать по date_format(date,%x-%v). При использовании group by year(date),week(date,3) получаем, что 29-31 декабря 2008 считается как 2008,1 неделя. Все логично, но следует помнить.
3) Статистика по табличкам, рекомендую сохранить как view.
SELECT table_name,engine,table_rows,
round(DATA_LENGTH/1024/1024,2) AS data_mb,
round(INDEX_LENGTH/1024/1024,2) AS index_mb,
round((DATA_LENGTH + INDEX_LENGTH)/1024/1024,2) AS total_mb 
FROM information_schema.tables where TABLE_SCHEMA = database();
4) Храним ip как UNSIGNED INTEGER для преобразования в строку используем inet_aton/inet_ntoa
5) Редкоиспользуемые данные выносим в отдельную таблицу с egnine=ARCHIVE
6) Дампы собираем сразу с gzip. mysqldump db |gzip > dump.gz. Распаковываем zcat dump.gz |mysql db
7) Правильно используем mysql из bash скрипта.
-N убирает название колонок таблицы
-B убирает псевдографику, используется таб как разделитель.
8) Забываем слово RAID5/RAID6. Для БД актуально только RAID10/RAID1
9) Если нужно уникальный индекс по большому текстовому полю, делаем еще одно с md5sum(textdata) и строим уникальный индекс по нему.

Если кому-то инетересен такой вариант полезных заметок, то продолжу отдельным постом
Определённо, ваши заметки мне нравятся больше, буду очень благодарен за пост в том же духе.
Интересно. Поделитесь опытом пожалуйста!
Очень полезные замечания.

Было бы очень хорошо, если бы вы написали полноценный пост.
Да, конечно же. Требуем!
Вам надо объеденить усилия)
6) Дампы собираем сразу с gzip. mysqldump db |gzip > dump.gz. Распаковываем zcat dump.gz |mysql db

а почему это лучше, чем mysqldump db >dump.sql && gzip dump.sql?
быстрее отработает дамп => меньше времени заблокирована запись в базу, нет?
Обычно не быстрее.
Запись на диск — медленная операция. Выгоднее писать на диск уже упакованные данные.
Продолжайте, только с пояснениями, пожалуйста.
Небольшой совет:

Для получения максимального/минимального значения лучше использовать SELECT… ORDER BY… LIMIT 1 чем SELECT MAX(...). Разница в скорости может достигать 6000 раз.

Наверное совет детский, но сам пару месяцев назад попался и был крайне удивлен.
Думаю правильнее попробовать и так и так, ибо не всегда ваше утверждение верно
Возможно. Просто натыкался я только на такое (с такой громадной разницей). Время выполнение было примерно 0.01с и 60с соответственно (на нагруженном сервере).
А всё зависит от индексов, которые будут использоваться для запроса.
Поэтому действительно, в каждом конкретном случае может быть как LIMIT быстрее, так и MAX не медленнее.
Всё очень просто, если у этого поля есть отдельный индекс, либо оно стоит первым по порядку в каком-то индекс, то max() будет очень быстрый.
Ну почти так, там еще есть нюансы касательно селективности и сортированности индекса, но эт действительно такие нюансы, которые не особо нужны новичкам.
Так ясен пень — вы смотрите на pdo времён его бытности независимым расширением.
С того же 2006 года pdo включено в ядро php, и искать его надо как-то так.
отсортируйте «как-то так» по дате.
может package2.xml, конечно, со времен pecl остался, но зачем им такой мусор в апстриме?
не, не лучше. но поискал по закрытым pdo-тикетам — действительно работают люди, я ошибался. чему рад :)
прошу прощения.
— А деньги лучше хранить в DECIMAL(10, 2)

Деньги лучше хранить умноженные на 100 в целочисленном виде, чтобы не налететь на ошибку округления.
С 5.1 можно хранить в decimal, не опасаясь налететь на ошибку округления.
Они переписали работу этого типа.
Я не имел ввиду базы данных вообще и MySQL в частности.
Из Вашего сообщения это не следует.
В целом же, могу сказать, что в основных промышленных (и некоторых непромышленных) уже всё хорошо с типами данных, отвечающими за деньги.

Хранение же в целочисленном виде тоже иногда чревато.
Особенно, если не подумав, начать хранить в int ;-)

Я этой темой первый раз заинтересовался, еще когда я жил в России: в приложении, написанном на PowerBuilder + Sybase баланс с партнером не сошелся на доли копейки при несколькомиллиардном обороте. Партнер сказал, что если есть разница в доли копейки, то может быть и разница в миллионы, так что пока все не сойдется в нули…

Тогровали сигаретами, если это кому-то сейчас что-то говорит, так что по поводу дальнейшего можно было бы написать хорошую статью на предмет мотивации.
Ну да, с тех времен у некоторых знакомых программистов осталась привычка делать сравнения не как
WHERE a = 1.5,
а как WHERE abs(a — 1.5) < 0.000001;

Я лишь к тому, что СУБД на месте тоже не стоят.
И что было справедливо 5-10 лет назад, сейчас уже может не соответствовать действительности. За последние годы на моей памяти весьма существенные изменения (я не про типы данных, а вообще) были как у бесплатных СУБД типа MySQL или PostgreSQL, так и у гигантов типа Oracle.
Это да. Я как-то года два назад пытался заставить Оракл ошибиться с округлением, не получилось.
У меня знакомые разработчики отказались в серьезной программе от использования копеек «потому что так проще» ©
Главное, об этом не забыть, когда на проекте целиком сменится команда ;-)
Как-то мне достался проект, в котором все ID во всех таблицах представляли собой смесь из MD5(CURRENT_TIMESTAMP+что-то ещё), вот было развлечение :)
Зачем Вы вводите людей в заблуждение, публикуя заметки, многие из которых морально устарели?

Полезно под каждую базу на боевом сервере создавать своего пользователя

Всё сильно зависит. На каждого пользователя у вас создается отдельный поток.
Соответственно, есть большая вероятность при большой нагрузке упереться в ограничения по потокам.

В большинстве случаев лучше использовать движок InnoDB

Я знаю только 1-2 случая, когда InnoDB не стоит использовать.

VARCHAR ограничена 255 символами, поэтому нет никакого смысла указывать VARCHAR(300)

Values in VARCHAR columns are variable-length strings. The length can be specified as a value from 0 to 65,535.
Я не говорю о больших и боевых серверах, конечно это заметка больше для начинающих.

Отдельная база — с разграничением прав — это дополнительная защита. Понятно что известный форум и информацию о кредитках хранить в одной базе очень рисковано.

Так я и говорю что лучше InnoDB использовать :-)

Про VARCHAR я действительно ошибался и постарался поскорее обновить пост.
Скорее правило:
Один пользователь на проэкт, да и это тоже не подходит.

Куда разумнее под «морду» давать ограниченную учетку без дропов, грантов и прочего, а для обновления базы создавать другую учетку, пользоваться рутом не комильфо.
«Я знаю только 1-2 случая, когда InnoDB не стоит использовать»
а можно рассказать по подробнее про эти случаи?
> mysqldump -u USER -pPASSWORD DATABASE > /path/to/file/dump.sql

Так могут быть проблемы, в общем случае так:

mysqldump -u USER -pPASSWORD --opt DATABASE > /path/to/file/dump.sql
В "--opt" входят: --add-drop-table, --add-locks, --create-options, --disable-keys, --extended-insert, --lock-tables, --quick, и --set-charset. Все они применяются по умолчанию, т.к. --opt во всех версиях по умолчанию включен. Чтобы отключить этот набор необходимо использовать --skip-opt
Что действительно стоит добавить, так это:
Для таблиц InnoDB надо добавлять --single-transaction, это гарантирует целостность данных бекапа. Для таблиц MyISAN это не актуально, ибо они не поддерживают транзакционность.
Спасибо, добавил
На мой взгляд стоит добавить:
GRANT ALL PRIVILEGES ON DATABASE.* TO USER@localhost IDENTIFIED BY 'PASSWORD';
Выполняю настолько же часто как приведённый вами набор комманд.
Спасибо добавлю
GRANT ALL — зло, зачем пользователю «морды» возможность DROP'а таблицы, базы? Это как рекомендовать везде использовать SELECT *
Ммммм… Понимаю. Правда шпаргалка явно для разработчика.
Про булевы значения может кто-то внятно объяснить, почему tinyint?
Конечно.

BOOL и BOOLEAN не поддерживаются в ANSI SQL, поэтому и официальная документация советует использовать TINYINT(1), т.е. по сути 1 байт
Так тогда вообще ENUM, он же для двух значений тоже байт будет занимать. Или я ошибаюсь?
А еще можно DECIMAL(1,0) — тоже будет один байт, но зачем?

Вариант с TINYINT(1) самый удобный.
В базах, которые доставались от других разработчиков, хранились в enum, поэтому и спрашиваю. Интересно чужое мнение.
Лучше TINYINT, ибо у ENUM всегда есть крошечный, но всё-же оверхед на выбор значения соответствующего строке.
Еще можно добавить что если нужно хранить много полей типа булеан, то их можно объединять в один *INT* и выбирать по битовой маске сразу несколько значений, например, те же правда на чтение/запись). В случае с ENUM это уже неудобно, а тип SET имеет очень много ограничений и неудобств в работе.
Еще рекомендую не экономить на спичках (еще один холивар?), давать запас IDшкам на следующие много-много лет и не надеятся на то, что лимит MEDIUMINT будет достигнут не раньше чем через 3 года.
Практика показывает, что за 2-3 года про ограничение уже никто не помнить (а может уже и некому будет помнить) и начинаются непонятные проблемы, причину которых найти не всегда просто, да и данных можно потерять вагон с небольшой тележкой.
Да-да, bigint рулит.
А у меня вот проблема — rand() стал изредка выдавать коллизии всего после пары миллионов айдишников =))
можно сделать concat(rand(),rand()) или rand()*rand(), есть куда фантазировать )
Да понятно, что можно. Можно даже залезть в сорцы и реализовать более стойкий к коллизиям алгоритм генерации псевдослучайного числа. Но сам факт меня опечалил, да.
хаха, rand()*rand() не даст более случайного «случайного числа», скорее наоборот.
А у меня вот проблема — rand() стал изредка выдавать коллизии всего после пары миллионов айдишников =))
Только один я заметил, что это программисткий анекдот?
а как вы с этим боретесь?
DATE, TIME, DATETIME — это по-сути строки, поэтому поиск и сравнение дат происходит через преобразование

Чушь спороли. date, datetime и time хранятся как инты, как в MyISAM (раздел «Storage Requirements for Date and Time Types in MyISAM»), так и в InnoDB, и так же сравниваются.
Спасибо поправил.
Сравнивая типы данных DATETIME и TIMESTAMP, не забывайте делать преобразование типов, например:
SELECT * FROM table WHERE `datetime` = DATE(`timestamp`)
на тех мускулях, где я работал — включение любой процедуры или преобразования в запрос значительно, на пару порядков, его замедляло. В узких местах такие вещи делать нельзя. Лечить денормализацией, «ночью по крону преобразовывать вручную к одному виду», и т.д.
Вплоть до одновременной записи в таблицу поля сразу в двух представлениях — таймстэмп и дейт-тайм.
Порой даже разделяя день, год, месяц, час, минуту и секунду по разным полям тини-инт (кроме года).
На свежих версиях не тестил, но у ребят из отдела программинга работа сайтов резко ускорилась на нём, после убивания преобразований внутри запросов.
Можно ещё разбивать сложный запрос на серию простых, с ручным использованием промежуточных php-переменных.

Особенно если надо сравнить со статичным значением, то вообще делать так:

$mydatetime = date('blablabla', $mybesttime);

mysql_query(«SELECT * FROM table WHERE `datetime` = '$mydatetime'»);
может быть они левое выражение преобразовывали?
то есть WHERE date(datetime) = timestamp — неправильно
WHERE datetime= DATE(timestamp) — правильно.
Заливаем архив бекапа в базу
gunzip < /path/to/outputfile.sql.gz | mysql -u USER -pPASSWORD DATABASE

zcat /path/to/outputfile.sql.gz | mysql -u USER -pPASSWORD DATABASE

И часто используется создание бекапа с указанием его даты
mysqldump -uUSER -pPASSWORD DATABASE | gzip > `date +/home/user/backup/dump.sql.%Y%m%d.%H%M%S.gz`
Спасибо, добавлю
Одно важное дополнение:

VARCHAR(65535) — это 64к символов. UTF-8 занимают 1-4 байта, но все же 1 символ.
TEXT — это 64к байтов.
>А деньги лучше хранить в DECIMAL(10, 2)

почему именно DECIMAL?
>mysqldump -u USER -pPASSWORD DATABASE > /path/to/file/dump.sql

mysqldump -u USER -pPASSWORD DATABASE -hSERVERNAME > /path/to/file/dump.sql
По умолчанию без указания -h будет подставлен localhost

mysqldump -u USER -pPASSWORD DATABASE TABLE > /path/to/file/dump_table.sql
Если нужно сделать дамп только одной таблицы
mysqldump -u USER -pPASSWORD DATABASE TABLE TABLE2 TABLE3… > /path/to/file/dump_tables.sql
Если нужно сделать дам нескольких таблиц
По мотивам статьи:

Как получить от сообщества полезную информацию? Кидаешь вброс, с любой осмысленной тарабарщиной. Люди начинают бурлеть и возмущенно но ценно комментировать. Постепенно вносишь правки в изначальный пост, и получаешь новые данные.
Можно назвать это «метод тетриса» или «каша из топора».

данный комментарий не относится конкретно к этой статье, она изначально уже была довольно граммотная.
Всё верно! Именно эту цель я и преследовал.

Я выкладываю то что знаю сам, при этом я не профессионал специализирующийся исключительно на БД.

Люди более опытные дополняют статью и делятся своими замечаниями, а я дополняю статью.

К чему всё это?..

А к тому, что сообществу нужны катализаторы! Нужны глупые статьи типа этой, которые провоцируют гуру писать свои архиполезные статьи и дельные замечания.

Мне нужны знания, опыт и общение, которые я получаю с подобных выпадов. А разве лично Вам не нужно то же самое? :-)
А если другие люди читают глупую статью и принимают ее за правильную? Это обществу точно не нужно.
«Глупая» — в данном случае следует читать как «набросок», а не как «набор вредных советов» :)

Хотя да… тут меня поправили пару раз, где я действительно изначально ошибался.
Для просмотра списка баз данных можно использовать команду:
mysqlshow -u USER -pPASSWORD

(часто ее использую перед восстановлением дампа)

А так же можно посмотреть список таблиц базы:
mysqlshow -u USER -pPASSWORD DATABASE
mysql > SHOW DATABASES;

:-)

Спасибо, дополню.
Но если нужно посмотреть всего лишь список баз данных, то это более быстрее :)
> удобно использовать бекап с дополнительными опциями -Q -c -e, т.е.
-Q и -e у mysqldump включаются по-умолчанию. А если цель — уменьшить размер дампа, что показывает применение -e, то и -c не нужен.
В общем, не нужен ни один ключ.
Вот еще неплохой скрипт для убивания висящих процессов в особо сложных для мускуля ситуациях (больному прописано давать раз в 5 минут):

— делаем SHOW PROCESSLIST
— нам выводится инфа вида

Id: 1
User: system user
Host:
db: NULL
Command: Connect
Time: 1030455
State: Waiting for master to send event
Info: NULL

— считаем сумму времени, прошедшего с начала выполнения каждого из запросов
— если сумма больше какого-то заданного числа, например, больше 600 секунд, делим ее на кол-во процессов
— через KILL убиваем все процессы, время выполнения которых больше нашего результата от деления. Можно еще добавить фильтр только на SELECT'ы.
— Profit!

ЗЫ: не говорите мне про архитектуру, оптимизацию БД и т.д. Способ подходит, если вам на поддержку дают проект, который был написан индусами или недобросовестными студентами первых курсов, не знаю, что хуже, и вам его нужно как можно быстрее оптимизировать (читай: что бы не глючил сайт на сервере)
zcat /path/to/outputfile.sql.gz | mysql -u USER -pPASSWORD DATABASE

это для импорта бекапа из архива gz, а не создание архивированного бекапа
Спасибо, поправил
Не ставьте для типа INTEGER свойство UNSIGNED, если вы не знаете что делайте. Из коробки php не поддерживает числа такого большого размера
PHP на 64 битной системе поддерживает целые числа вплоть до BIGINT со знаком.
Спасибо, поправил
Где-то не там и не туда поправлено :)
Или мой комментарий был неправильно понят.
Возможно…

Пожалуйста, предложите свою альтернативу

Не ставьте для типа INTEGER свойство UNSIGNED, если вы не знаете что делайте. Из коробки php не поддерживает числа такого большого размера на 32-битных системах.
А, вот теперь вижу исправления.
Только не пойму, зачем старая не исправленная фраза в конец статьи попала. Видимо из-за этого я и не увидел исправлений выше :)
Спасибо за критику, надеюсь что сейчас мы пришли к компромису :)

На 32-битных системах практически нет смысла ставить для типа INTEGER свойство UNSIGNED, так как такие большие числа в php не поддерживаются.
На 64-битных системах, php поддерживает большие числа, вплоть до MySQL BIGINT со знаком.
Почти. Я уже не про исправление насчет 32/64 битных систем писал последний раз, а про то, что в конце статьи не нужный текст попал. И так он там до сих пор и остался.
Спасибо за критику, надеюсь что сейчас мы пришли к компромису :)

На 32-битных системах практически нет смысла ставить для типа INTEGER свойство UNSIGNED, так как такие большие числа в php не поддерживаются.
На 64-битных системах, php поддерживает большие числа, вплоть до MySQL BIGINT со знаком.
спасибо, всё полезное и на одной странице. в закладки конечно же
> А деньги лучше хранить в DECIMAL(10, 2)

Почему лучше? Кому лучше? Что, прям вот всегда две цифры после запятой?
saunalahti.fi/gsm/ — три цифры после запятой в тарифах (а где-то в рекламе вообще 4 цифры видел). В Европе будете, там, где цены в евро — посмотрите цены на заправках, тоже три цифры встречаются.

Вредный, опасный совет.
> Связанные таблицы («Foreign keys») должны иметь полное сходство по структуре ключей. Т.е. если у нас на одной таблице для поля указано «INTEGER UNSIGNED DEFAULT 0 NOT NULL» то и на другой должно быть указано аналогично

категорически не согласен. тип один и тот же да. но вот про значение по умолчанию и null / не null не согласен.
почитайте книжки про базы данных — помимо отношений (relations) между таблицами, существует еще такое понятие как «класс принадлежности», если не ошибаюсь оно так называется.
Так вот, по вашему получается, что класс принадлежности всегда является обязательным.
Простой пример. Есть в базе сущность «новости» и есть сущность «категории новостей». Новость с помощью foreign key привязана к категории, у которой, само собой, есть id и который, естественно not null. Но если поле, у сущности «новости», которое связывает эту таблицу с категориями будет тоже not null, то мы не сможем создать новость, которая не принадлежит ни одной категории, а это для многих случаев не верно.
Вы говорите всё верно, если дело касается NOTNULL и DEFAULT VALUE.

Я не заострял на этом внимание что бы сократить абзац.
Так же можно делать бэкап перечисленных database, добавив --database и перечислив все необходимые базы.
Я бы не светил пароль от базы в истории команд терминала. Это как-то не очень.

Хорошим тоном (особенно в cron-задачах) считаю чтение паролей из файла:

# Файл `credentials.cnf` формата как `/etc/mysql/debian.cnf` с одной секцией [client].
# Выставить для файла минимально необходимые права для чтения.
[client]
host     = localhost
user     = username
password = password
# socket = /var/run/mysqld/mysqld.sock


Запускать тогда так:

mysqldump  --defaults-extra-file='/path/to/credentials.cnf'  dbname
TEXT ограничен только 64 килобитами


килобайтами
mysqldump -u USER -pPASSWORD DATABASE -hSERVERNAME > /path/to/file/dump.sql
По умолчанию без указания -h будет подставлен localhost

Добавьте — правда не хватает!

Sign up to leave a comment.

Articles