Всем привет! Я думаю у многих начинающих программистов рано или поздно возникают вопросы по поводу того на сколько правильно я создаю базы данных и формирую запросы к ним. В этой теме предлагаю разобрать наиболее часто встречающиеся проблемы и пути их решения. Всем откликнувшимся заранее благодарен!
Тут же предлагаю следующую ситуацию: Есть 2 таблицы: 1 - таблица отелей; 2 - таблица (с параметрами) например: джакузи в номере, телефон, телевизор короче не суть важно (их около сотни). Внимание вопрос! Каким образом наиболее правильно сформировать связь между этими таблицами так чтобы при добавлении нового отеля можно было выбрать несколько параметров и сохранить эту информацию.
Мое видение (может оно идиотское) но пока другого не пришло При выборе параметров я формирую из id (параметров) строку с разделителями и сохраняю в таблицу с отелями. все бы ни чего, но когда доходит дело до поиска по отелям с заданными параметрами - дело плохо, ничего умнее как формировать запрос с кучей [sql] SELECT * FROM `hotels` WHERE params LIKE '%,1,%' AND params LIKE '%,20,%'[/sql] и т.д. но параметров много и этот запрос превращается в километровую строку. У меня такое чувство что что-то здесь не так Всем спасибо за помощь.
Danil Добавлять поля jacuzzi, phone, tv и т. д. (с типом TINYINT(1)) в таблицу отелей. 100 полей - это конечно сильно, но все равно лучше других решений типа дополнительных таблиц или поиска через LIKE. Запросы будут выглядеть так: [sql]SELECT * FROM hotels WHERE phone=1 AND tv=1[/sql] И самому понятнее, и скорость выборки по максимуму (особенно если на наиболее популярные параметры навесить индексы).
Спасибо, но дело в том что количество параметров может увеличиваться. Как с этим быть добавлять поля в таблицу? Можно конечно, но мне кажется возможно лучшее решение (жаль только я его не знаю )
Danil Да, разумеется. Запросы ALTER TABLE не просто так придуманы Лучшее ли - не знаю... можно завести таблицу, связывающую отели и параметры. С полями hotelid, paramid. И условиться: если в этой таблице есть строка с некими hotelid и paramid - значит, данный параметр у данного отеля включен. Так можно чуть ускорить твою выборку (см. ниже). Но и у этого метода полно недостатков. [sql]SELECT * FROM hotels WHERE id IN (SELECT DISTINCT(hotelid) FROM hotelparams WHERE paramid IN (1,20))[/sql]
Упс, запрос выше - не для твоего случая. Это если устраивает любой из параметров. Ладно, для случая AND пусть кто-нибудь другой запрос напишет
Тоже есть вопрос. Есть сайт с объявлениями о продаже недвижимости. Человек заходит и хочет сделать запрос и чтобы по этому запросу потом обрабатывались новые объявления. В запросе, в том числе, будут указаны станции метро, на которых интерисует квартира. Как лучше хранить эти станции метро? Я видел вариант (и сейчас с ним работаю) когда id - шники метро хранятся в текстовом поле таблицы filtr с фильтрами объявлений, например [sql],12,45,112,62,[/sql] и потом идет выборка (в триггере, при добавлении нового объявления смотрим есть ли подходящие фильтры) [sql]WHERE filtr.idmetro LIKE CONCAT("%,",new.idmetro,",%")[/sql]. Вроде все работает и довольно быстро. И добавить можно хоть вообще все станции. Но, неправильнее ли будет сделать отдельную таблицу, где будут храниться все эти id шники метро?
Так как тогда быть? Создавать новую таблицу, в которой будет id_filter, id_metro Но тогда, получается: 30 заявок, в каждой по 10 станций метро = 300 записей в таблице. А так, просто в таблице filtr будет поле TEXT - в которой все idшники будут храниться через запятую Как лучше?
задачи для баз в 10000 записей вообще можно делать как угодно, хоть через жопу, хоть в FULLTEXT все пихать. MySQL съест все это не поперхнувшись. задачи "правильной" организации базы возникают когда проект вырастает по нагрузке и объемам, а вот тут как раз и не катят стандартные методы решения. к примеру о тех же метро. имеем. 100000 записей о людях/персонах и 100 о станциях метро нам нжно установить связь с теми станциями метро где челове живет и работает (2-4 стнции) стандартным решением является НОРМАЛИЗАЦИЯ базы персона id,name связь idname,idmetro метро id,metro тогда SQL выборки бдут стандатрными. обычный JOIN или как-то так, НО обратим внимание на объемы котоые мускулю нужно будет обработать при таких зпросах. 100 000*100 = 100 000 000 это уже МНОГОВА-то, а если нам надо на странице отобразить всего 20 человек, то лоптить такие объемы совсем не катит. делаем просто поле text и пихаем туда сериализованный массив со станциями метро. имеем: одн таблицу. однопроходную выборку с LIKE. прирост производиительности в РАЗЫ. Проверено на реальных объемах. прикинте объемы при 2-3-4 таких связях, а в нормальных ьбазах это как минимум и те обюъемы записей которые будет mysql лопатить для вывода 20 персон. =)))))))))))))))
Когда у меня была та же проблема выбора нашел вот такую функцию может кому пригодится [sql]FIND_IN_SET(str,strlist)[/sql] Возвращает значение от 1 до N, если строка str присутствует в списке strlist, состоящем из N подстрок. Список строк представляет собой строку, состоящую из подстрок, разделенных символами ','. Если первый аргумент представляет собой строку констант, а второй является столбцом типа SET, функция FIND_IN_SET() оптимизируется для использования двоичной арифметики! Возвращает 0, если str отсутствует в списке strlist или если strlist является пустой строкой. Если один из аргументов равен NULL, возвращается 0. Данная функция не будет корректно работать, если первый аргумент содержит символ ',': [sql]mysql> SELECT FIND_IN_SET('b','a,b,c,d'); -> 2[/sql]
я те 100 0примеров риведу когда индексы ТОРМОЗЯТ. Когда что бы все работло сначла индексы удаляют, потом производят операции, а потом опять их создают. =) не надо вбивать себе в голову, что небо синее, а вода мокрая. Надо посмотреть на небо и потрогать воду. Перебор 100 000 000 записей (это для одной связи) хоть с десятком индексов куда как медленее простого перебора 100 000. уж поверь. да сам подумай да посчитай.
от понимания процесса это зависит, а не от того, что "индексы бстро". нихрена не быстро при определенных задачах.
угу. в твоем примере так имеет смысл, пока надо искать только с одной стороны. Как только потребуется найти людей близких к этому метро - ты умрешь.
Вот еще один вопросик. Думаю должен быть актуальным. Пусть есть таблица людей или фирм кого угодно, которые размещают объявления с оплатой на какое-то количество дней и датой публикации. Необходимо сформировать запрос который выводит эти объявления одновременно проверяя не просрочены ли они и если просрочены то сбрасывает их (не удаляет, а просто отмечает что их показывать не надо)
Во вроде бы что-то типа такого должно сработать Если в поле pubdate хранится дата публикации, а в days количество оплаченных дней pay - это просто флаг который нужен для последующей выборки [sql]UPDATE company_table SET pay = TO_DAYS(NOW()) - TO_DAYS(pubdate) < days[/sql]