--}}
Новая тема
Вы не можете создавать новые темы.
Т.к. вы неавторизованы на сайте. Пожалуйста назовите себя или зарегистрируйтесь.
Список тем

Что лучше: PHP или SQL?

Нужен совет (поиск решения проблемы. не для купли-продажи)
655
75
С друзьями на NN.RU
В социальных сетях
Поделиться
Дано: проектик, который запрашивает данные из базы и выводит их в формы.
Некоторые данные для получения требуют вложенных запросов.

Что лучше: описывать эти запросы в PHP, запрашивая данные хитрыми семиэтажными способами или просто добавить в базу SQL хранимые процедуры?

С одной стороны по опыту скажу: с хранимыми процедурами всё гораздо проще.
С другой стороны, я слышал, они сильно нагружают сервер. Ну так и хитрые PHP-запросы нагрузят сервер не меньше, разве нет?

Если требуются конкретные параметры, то:
система OpenBSD-6.4 amd64, вебсервер nginx-1.14.0
PHP версии: 7.2.10
SQL: mariadb-server-10.0.36p0v1
Все данные в базе хранятся в utf8, collate=utf8_unicode_ci
Для всех таблиц установлен движок Aria, доступы к php и sql через файловые сокеты.

В общем, кто что может сказать по этому поводу?
Афраний писал(а)
хитрые PHP-запросы нагрузят сервер не меньше

что за запросы?
Допустим, есть жёстко зашитый список товаров (таблица goods). Для каждого товара имеется картинка. Товары имеют определённые категории (таблица categories). А ещё товар с одним и тем же названием может быть в нескольких разных вариантах фасовки. Допустим, пицца разных диаметров. Поэтому есть таблица для описания реальных товаров (goods_real), в которой указан параметр нетто и его единица измерения (вес в граммах, объём в миллилитрах или диаметр пиццы в сантиметрах). Соответственно, торговая точка выбирает товары из списка и хранит свой ассортимент (таблица goods_shop). Там же указана цена товара и его наличие.

А теперь нам надо вывести список всех товаров в магазине...
Я пока не добавил наличие и название категории, но запрос выглядит примерно так:
SELECT _id,rgid,(SELECT goods FROM goods_real WHERE rgid=goods_shop.rgid) as ggid,(SELECT categ FROM goods WHERE goods.goods=ggid) as categ,price,(SELECT netto FROM goods_real WHERE rgid=goods_shop.rgid) as netto,(SELECT measure FROM goods WHERE goods.goods=ggid) as measure,(SELECT gimg FROM goods WHERE goods.goods=ggid) as pic,(SELECT title FROM goods WHERE goods.goods=ggid) as title FROM goods_shop WHERE shop_id=1;
По-моему, достаточно просто реляций (OneToMany и т.п.). Хранимые процедуры тут ни к чему.
Может быть. Спасибо за подсказку, буду иметь в виду.
Gavrosh
26.08.2019
Афраний писал(а)
SELECT _id,rgid,(SELECT goods FROM goods_real WHERE rgid=goods_shop.rgid) as ggid,(SELECT categ FROM goods WHERE goods.goods=ggid) as categ,price,(SELECT netto FROM goods_real WHERE rgid=goods_shop.rgid) as netto,(SELECT measure FROM goods WHERE goods.goods=ggid) as measure,(SELECT gimg FROM goods WHERE goods.goods=ggid) as pic,(SELECT title FROM goods WHERE goods.goods=ggid) as title FROM goods_shop WHERE shop_id=1;

запрос ужасен, имхо. просто почитайте про sql ansi 92, архитектуру данных, констрайнты и индексы и т.п.
считается хорошей практикой делать отбор данных серверной математикой. вывод на морду - кто на чём привык. хоть пхп, хоть джава хоть питон
Gavrosh писал(а)
запрос ужасен, имхо.
ИМХО, тоже, но главное - по факту он работает.

И что печальнее всего - пока никто ничего лучше не предложил.
Gavrosh писал(а)
просто почитайте про sql ansi 92, архитектуру данных, констрайнты и индексы и т.п.
Простите, тяжёлое наследие FoxPro for DOS даёт о себе знать :-)
Gavrosh писал(а)
считается хорошей практикой делать отбор данных серверной математикой.
PHP выполняется на сервере.
А с выводом на морду данных в формате JSON я уж как-нибудь разберусь.
Gavrosh
26.08.2019
Афраний писал(а)
ИМХО, тоже, но главное - по факту он работает.

Да, он работает и правильные результаты выдаёт. На тесте, где 10-100-1000 записей и один юзер, даже мгновенно. Если будет прод - это вилы.
Кхм... А если подумать - зачем я сюда пишу?
Какие вопросы меня беспокоят? Правильно - производительность.
Именно с этой целью я и спрашиваю, как оптимизировать запросы.
То ли в хранимые процедуры их загнать, то ли вот такие составные делать, то ли использовать несколько запросов в одной php-процедуре...

Поэтому... Если будет прод - что Вы могли бы предложить?

P.P.S. именно этот запрос для производительности не критичен: товаров немного. Но есть и другие запросы, почему и спрашиваю.
Gavrosh
26.08.2019
Ну, вряд ли тут в рамках топика вас кто то научит "как правильно".
Вашу конструкцию можно переиначить, например
create view Main_view as
select * from (
SELECT _id,shop_id, rgid,
(SELECT goods FROM goods_real WHERE rgid=goods_shop.rgid) as ggid,
(SELECT categ FROM goods WHERE goods.goods=ggid) as categ,
price,
(SELECT netto FROM goods_real WHERE rgid=goods_shop.rgid) as netto,
(SELECT measure FROM goods WHERE goods.goods=ggid) as measure,
(SELECT gimg FROM goods WHERE goods.goods=ggid) as pic,
(SELECT title FROM goods WHERE goods.goods=ggid) as title
FROM goods_shop ) shops

И ваш запрос будет выглядеть как select * from Main_view;
И всё всех будет устраивать и поля в морду браться будут из него.
Но может оказаться что всё медленно и печально. Или поле price требует историчности, клиент заказал шаверму по старой цене, ему отгрузили по новой, он в гневе. Наработки морды вы не меняете, поскольку поля те же. Но меняете/оптимизируете запрос во вьюшке Main_view, и всё становится в ёлочку.
Нет, поле Price меняется моментально и клиент априори не может заказать товар по иной цене.
Есть четыре таблицы, данные из которых должны быть взяты и отображены одним запросом.
categ - содержит имена категорий
goods - содержит имена и картинки товаров
goods_real - содержит варианты фасовки
goods_shop - содержит ВСЕ товары ВСЕХ магазинов. С указанием цены и комментария.
Собственно, к последней таблице и делается запрос с указанием ID магазина.
А все остальные бубны нужны только для получения типа фасовки (веса и измерения в граммах, объёма и измерения в миллилитрах), наименования товара и его изображения, наименования категории...

Если есть вариант, как это сделать иначе, буду рад узнать.
Gavrosh
26.08.2019
Мне кажется, у вас что-то не так с диаграммой entity-relations.
Определите набор сущностей и их атрибутов, так чтобы не было их дублирования. Постройте между ними связи и ограничения целостности. Просто ручкой на бумажке. Ошибки стадии архитектуры данных - самые дорогие в исправлении.

И да. Именование - это важно. Если вы не можете подобрать слова, чтобы определить "эту фигню", может оказаться что она и не нужна, или вместо неё надо завести несколько фигней. В вашей схеме неочевидно предназначение сущностей.

Цена - обязательно должна быть историчной. Клиент заказал шаверму по 100 р. Через 5 минут после этого Маша решила что пора что то менять и поставила цену 120. Её испекли, упаковали и ордер отправился по маршруту с ценой 120. Кроме того, обязательно потребуются отчёты, а они не будут бить. Отчёт, выпущеный сегодня никогда не сойдётся с таким же выпущенным месяц назад, коммерсов это сильно напрягает.
Всё уже определено.
Клиент добавил в корзину шаверму по 100 рублей.
Через 5 минут после этого Маша решила, что пора что-то менять и поставила цену 120. В магазине.

А в корзине клиента цена по прежнему 100. И если клиент её не выложит и не положит новую по 120, то он и через неделю сделает заказ - по 100.

Отчётов не предусмотрено. Никаких. Кроме выставленных и оплаченных счетов. Их можно суммировать и проанализировать - по общей сумме проданного, по количеству проданных товаров. Но не более того.

А дублирования у меня нет. Ну разве что ID товара и ID реального товара в нескольких таблицах - но по сути это Foreign Key
Psycho
26.08.2019
5 вложенных select и from. Еще добавим order by date, пару отборов, сортировку и можно ждать тему "У меня 12 ядер, 64 рамы, nvme и все тормозит, что делать? " ))
Афраний писал(а)
И что печальнее всего - пока никто ничего лучше не предложил.

Используй ORM, а с тонкостями SQL потом разберёшься :-D
martovsky
01.09.2019
Под нагрузку я бы сделал проще - агрегированную таблицу с избыточными данными, триггерами и констрейтами на соотносящиеся данные, и индексами под конкретные запросы.

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

Можно пример?
martovsky
01.09.2019
А я без ER модели даже примерно не скажу.

Советовал бы попробовать начать с ER. Программ много есть.
Типа так --->
Вот финальная версия запроса --->
Psycho
26.08.2019
1. В 9 случаев из 10 хранимые быстрее.
2. Как нравится так и делай, с хранимыми права проще будет разрулить (если надо), как минимум.

От запроса глаза закровоточили, это что? JOIN для кого придуман ?
Psycho
26.08.2019
Еще раз прочитал условия.
Единицу измерения лучше перетащить к SKU это сильно все упростит, а значение справочно - хранить уже отдельно. Могу быть не прав, конечного замысла не знаю.

Категорию можно сделать как parent в goods, минус лишняя таблица, на вкус и цвет.

Хранит ассортимент, цену, остатки goods_shop....
Я бы разделил.
Отдельно прайс, отдельно стоки.

И вообще для таких запросов достаточно вьюшку сделать, будет еще проще.
Спасибо, конечно, я просто SQL ещё не сильно хорошо знаю и не слишком активно работал с JOIN. SKU - это что?

Замысел: продавцы в свой ассортимент берут товары из списка, но при этом могут указывать свою цену и свой комментарий.
По наличию есть два варианта: либо учитывать, либо нет.
То есть если наличие не учитывается, клиент может хоть миллион экземпляров товара заказать. Если учитывается, то клиент закажет не больше, чем есть в наличии - но тогда продавцу нужно будет держать эти цифры актуальными.

Категории товаров имеют древовидную структуру.
Psycho
26.08.2019
Если как ты писал выше, у тебя есть
Шаверма от Ашота в goods
и есть
50 гр.
100 гр.
150 гр.
Распиханные в goods_real

SKU - это _конкретный_ товар, в нашем случае Шаверма от Ашота + 50 гр.
Это реализуется через Foreign Key, но ARIA в него не умеет, лучше документацию глянуть.
Можно обойтись костылем, и хранить id goods_real в goods и каждый раз это кодом обрабатывать.

Дерево можно строить и по одной таблице


А можно завести в goods
id name
1 Шаверма от Ашота 50 гр.
2 Шаверма от Ашота 100 гр.
3 Шаверма от Ашота 150 гр.
Ключ таблицы goods уникален будет в данном случае.
Psycho писал(а)
Это реализуется через Foreign Key, но ARIA в него не умеет,
Фигня вопрос, XtraDB есть
Psycho писал(а)
Дерево можно строить и по одной таблице
Так и делаю.
Psycho писал(а)
А можно завести в goods
id name
1 Шаверма от Ашота 50 гр.
2 Шаверма от Ашота 100 гр.
3 Шаверма от Ашота 150 гр.
Ключ таблицы goods уникален будет в данном случае
Меня интересует не уникальность ключа, а чтобы наименования одного и того же товара были одинаковыми. И картинки - тоже.

По факту - пишется приложение для ВК, а поскольку ресурсы у меня лично не резиновые, хотелось бы, чтобы пользователи могли добавлять только текстовую информацию - и то в минимальном объёме.

Но если честно, у меня и база толком не спроектирована. Все упущения переделываю прямо в процессе.
Psycho
26.08.2019
Афраний писал(а)
Но если честно, у меня и база толком не спроектирована. Все упущения переделываю прямо в процессе.


Ключевой момент. Выше критика запроса - потому что ты пытаешься выбрать данные из "базы" которая фактически является в твоем случае набором таблиц, которые построены без учета каких либо механизмов СУБД в принципе.
Если бы я ещё знал эти механизмы :-)

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

Что я хочу - примерно описал в текстовом файле.
Файл в аттаче.
К сообщению прикреплен файл:
236988696-brsjvk-zap.txt   (7 Kb)   Скачать файл
Psycho
26.08.2019
Даже хотелки описаны скудно, мягко говоря.
Прямо по файлу:
1. Пользователи - допустим.

>>Подразумевается, что доставка производится в пределах населённого пункта (города)
Я бы не подразумевал, буду исключения 100%.

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

3. У юриков сильно больше требуемых данных, ни тебе КПП, ни отделения банка...

4. Адреса юриков лежат там же где физики выше.
1. Не "допустим", а точно. Я не хочу, чтобы пользователь во Владивостоке себе суши из Калининграда заказывал. Поэтому такое вот программное ограничение. Исключений не предусмотрено.
2. Адреса и вынесены в отдельную таблицу. Строками - ибо классификатор на фиг не нужен. Пусть хоть на остановку автобуса доставку заказывают.
2.1. Номер кошелька ЯД нужен ТОЛЬКО участникам ПЛ и ТОЛЬКО для выплаты вознаграждения ИМ. Владельцы магазинов выбирают свои варианты оплаты, вариант с картой Сбера в списке есть.
3. Нет, этого достаточно. Тем более, 90 процентов продаванов - это ИП Ашота, а всякие КПП при необходимости можно запросить дополнительно, зная дату регистрации и ОГРН.
4. Нет. У физиков город указан индексом главпочтамта, но для юриков точность индекса важнее. Так что там должна быть не только улица и дом, но и город, область край - и правильный почтовый индекс.

Сразу уточню: система рассчитана не на мегаполисы, а на райцентры.
И вот примерный портрет того, для кого это всё и пишется:
vk.com/umangala030218
Psycho
26.08.2019
1. Т.е я прилетел из Владика в Калининград и сиди голодным ? ) Или жене хочу заказать. Я клиент, и деньги хочу потратить, а мне типа иннах ? )
Даже в НН, многие службы доставки доставляют не во все районы. 100% такое в каком нибудь Усть-Пердяевске вылезет.
2. Ну и будет через год база кучей говна из которой ты никакой аналитики толком не получишь, не геопривязки, и придется тебе потом пол-года руками данные анализировать. Взял КЛАДР из 1С и распарсил его в базу, делов на пол дня.

4. Нафига в базе дублировать одинаковую информацию?! В одном месте это хранить надо и получать ссылкой. Это СУБД а не блокнот.
Psycho писал(а)
1.1 Т.е я прилетел из Владика в Калининград и сиди голодным ? )
Зачем? Просто меняете город пребывания в настройках. Это не намертво зашитая константа.
Psycho писал(а)
1.2 Даже в НН, многие службы доставки доставляют не во все районы.
Это проблема мегаполиса. Не можешь доставлять по всему городу - уступи место тем, кто может.
Psycho писал(а)
2. Ну и будет через год база кучей говна из которой ты никакой аналитики толком не получишь,
А на фиг мне эта аналитика? В КЛАДР тоже геопривязки нет. А так у меня геопривязка к каждому городу. КЛАДР я могу взять не только из 1С и даже распарсить в базу его могу. Я потом не нарисую для него интерфейс. Если для тебя это "делов на полдня", то мне - на две недели.
Psycho писал(а)
4.4. Нафига в базе дублировать одинаковую информацию?!
Это какую? Адреса разные. Я напомню: это не телефонная база данных, где в каждом доме имеется телефон. Вот есть улица. На ней 100 домов - это 100 адресов. Из них фастфуд закажут максимум пятеро. На хера мне ради этих пятерых на всю улицу КЛАДР прикручивать?
UPD. Тем более, в КЛАДР куча сёл и деревень, в которых шаурмячных и пиццерий отродясь не бывало.
Psycho
26.08.2019
То, что ниже - считай вода, нет конкретики.

Пойми главное, структура СУБД проектируется под конкретные данные, а у тебя описания кот наплакал даже функционально.

Просто вопросы на вскидку:
Как попадают справочные данные в базу ? (Товары, цены, _остатки_) ?
Как происходит работа с заказами (изменение статуса, изменение состава, отмена, и.т.д)
Структура данных хранения заказа (Более свежие релизы MariaDB например умеют хранить данные в формате JSON, и там много чего для этого добавлено.)
История заказов нужна ? Храним статично (все данные заказа в том же JSON) или собираем запросом по базе (от этого например зависит структура хранения цен, таблица должны быть периодической, с нюансами).
Маркетинговый блок (скидочные карты, промокоды, купоны, прочая херня) ?
От маркетинга спляшет хранение заказов (как храним скидки, или цену без скидки и цену со скидкой, построчно или на чек, как округляем, и.т.д).
Обмены с другими системами?

Вопросов много на самом деле.
Начни с нормального описания по каждому блоку. Потом под каждый блок описание данных и типов и допустимых значений. А потом уже увязывай это все вместе в виде схемы базы.
Навскидку ответы:
1. Товары жёстко прошиты в базу. Ассортимент конкретного магазина выбирает владелец. Он же указывает цены и комментарии. Остатки указывать не обязательно (на усмотрение владельца). Если ларёк торгует шавермой, им неинтересно указывать "вот мы сегодня сделали 73 шавермы с курицей и 58 со свининой". Им это просто на хер не упёрлось.
2. Структура хранения заказов есть. Просто есть таблица заказов. У каждого заказа есть состояние (выставлен, оплачен, исполнен). В принципе, можно поднять историю исполненных заказов. Хоть по клиенту, хоть по магазину.
Отдельно таблица товаров в заказе - с привязкой к заказу.
Заказ считается как: сумма стоимости всех товаров (с указанием их количества) плюс стоимость доставки (если она не превышает сумму бесплатной доставки, иначе 0). Общая стоимость заказа прописывается в самом заказе.
3. Маркетинговый блок - на данном этапе не предусмотрен. Совсем. Никаких скидок, никаких вариантов обмена с другими системами.

Вся БД в том виде, в каком она есть сейчас - в аттаче. Да, сырая.
К сообщению прикреплен файл:
237000210-fooddb.7z   (21 Kb)   Скачать файл
Psycho
26.08.2019
Default 0 - убирай, вообще везде, он объективно нужен только где лояльность.

Прайсы выноси в отдельную таблицу и пихай связь shop_id, goods_id/

goods_order (
_id INT NOT NULL default 0, /* id товара */
shopid INT NOT NULL default 0, /* id магазина */
cartid INT NOT NULL default 0, /* id корзины */
price INT NOT NULL default 0, /* цена товара за штуку */
numberOf INT NOT NULL default 0, /* количество товара с этим id */
PRIMARY KEY (_id)
) ENGINE=Aria;

Уникальный ключ для товара ? Т.е один товар можно заказать только один раз ?

price INT - элегантно решаем проблему копеек )

Passwd VARCHAR(48) - секьюрно.

Phone VARCHAR(10) - ну такое.

Многие процедуры не понятно зачем.

Генерация id тикетов - автоинкремент чем не устраивает? Избыточно.

Запись не в транзакции ? Удачи в отладке.

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

Прайс для каждого магазина свой.

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

Это имеет смысл для групповых заказов - например, для сотрудников отдела в офис.
MonitoR
25.08.2019
лучше питон и тарантул блеать :) лучше в каждом случае разное. угадать что такое лучше в этом конкретном случае без примера - разговор ни о чем. :)
Psycho
26.08.2019
Афраний писал(а)
Aria


Mariadb дремучая больно. Обновляйся и уходи на INNODB.
1. В смысле "дремучая"?
2. Почему не на XtraDB?
Psycho
26.08.2019
1. Старая версия.
2. А что там есть такого, что ты реально планируешь использовать ? Зачем усложнять ?
1. Версии я ставлю из пакаджей, если ставить 10.0.0.38, то желательно переходить на 6.5
2. Да тут как раз наоборот подсказывают, что Aria не имеет нужных функций. И так-то есть до фига чего, что планируется к использованию.

Может и имеет смысл перейти на InnoDB/ XtraDB
Тоже мне старая. Прошлогодняя. Август 2018.
Psycho
27.08.2019
Разобрался бы хоть немного в вопросе перед тем как делать выводы.
10.0 Старая поддерживаемая ветка.

А есть 10.2, 10.3, 10.4, которые по функционалу мягко говоря отличаются.
А тут они есть?
mirror.yandex.ru/pub/OpenBSD/6.5/packages/amd64/

Ветка поддерживаемая - это главное.
Psycho
27.08.2019
Ну если тебя нравится bdsm с полутрупом собери из сырцов.

Веселит твоя позиция, прошу советов, но с советами спорю, сам умнее. "На зло мамке уши отморожу".
Успехов.
Почему полутрупом? Система вполне живая и в ней нет ничего лишнего.
Простая и безопасная. И к ресурсам относится экономно.

Да, я прошу совета. Мне этот функционал нужен или я смогу обойтись без него?

Как видите, я до сих пор на 6.4, хотя 6.5 вышла ещё весной.
Просто мне была нужна вещь, которая работает на PHP-5.6 - а в 6.5 его уже нет.
Есть 7.0 7.1 7.2 и 7.3

Я понимаю, что в новые версии ПО добавляют новые плюшки и функции.
Однако осмелюсь напомнить - я пока и старые-то ещё не изучил.
Psycho
27.08.2019
Афраний писал(а)
Я понимаю, что в новые версии ПО добавляют новые плюшки и функции.
Однако осмелюсь напомнить - я пока и старые-то ещё не изучил.


Мне что бы теслу водить начинать надо с парового автомобиля, или уж сразу с лошади с телегой ?
Psycho
27.08.2019
Много советов насыпали уже, самый важный выше дал Gavrosh
"Ошибки стадии архитектуры данных - самые дорогие в исправлении."

Ты пытаешься всех убедить непонятно в чем, противоположном.
Действительно думаешь что тебя тут в чем-то будут убеждать тратя свое время на тебя?

Тезисы следующие:
1. Ни какой некрофилии. Свежий массовый линукс, докер, официальные образы.
2. Пакеты - максимально свежие, стабильные. Баги есть в любых, свежие более оперативно фиксятся.
3. Перед тем как что-то сделать - проектируй. Ошибки могут стоить дикого количества твоего же времени на переделку.
4. Продумай бизнес-логику приложения. Любое действие должно иметь обратный эффект. Предусмотри максимальное количество разрезов аналитики, даже если они не нужны.
5. Можно использовать что-то унифицированное типа того же кладр - используй.
6. То что писали выше, про периодические прайсы, данные для отчетов, транзакционность и.т.д - делай, даже если на данном этапе не надо. И если не понимаешь зачем - все равно делай ). Потом это будет сильно сложнее реализовать.
7. Тестируйся на реальных объемах данных, сгенерировать десяток милллионов записей не сложно, зато открытий неожиданных будет масса.

Не устраивает написанное выше ? Ну делай как сам знаешь.
Понял, спасибо.

С Windows 7 на Windows 10 тоже уже пора переходить или ещё посидеть можно? (к вопросу о некрофилии).

Пункты 2,3,6,7 принял к сведению, благодарю.
С пункта 4, собственно говоря, начал.
По поводу аналитики - смотреть её я не в ВК собираюсь.
То есть она будет, но отдельным приложением.
С пунктом 5 пока затык... К сожалению, я не настолько опытен, извините.
Может имеет смысл кого-то нанять на эту работу? Дорого обойдётся?
Посмотрел варианты - кажется, с КЛАДР ожидается пушной зверёк.
В своих целях его использовать - пожалуйста, а в коммерческих - запрещено.
Psycho
27.08.2019
Хз где ты смотрел, читай лицензию
www.gnivc.ru/technical_support/classifiers_reference/kladr/
О том и речь:

Пользователь КЛАДР обязуется не распространять КЛАДР. Под распространением понимается предоставление доступа третьим лицам к воспроизведенной в любой форме КЛАДР и ее компонентам путем продажи, проката, сдачи внаем, предоставления взаймы или иными способами отчуждения.
Psycho
27.08.2019
Ты же не отчуждаешь )
Если продаваны за доступ к моему приложению платят - юридически можно придраться, что я типа в составе своего приложения предоставляю доступ к КЛАДР третьим лицам напрокат.
Тем более я прошу совета, как оптимизировать существующую инфраструктуру, а не перейти на более новую.

Я могу рассмотреть вариант перехода на новую инфраструктуру при условии, что она будет работать намного быстрее старой.
"которые по функционалу мягко говоря отличаются" - а мне это сильно поможет в оптимизации? Пример можно?
Psycho
27.08.2019
Чего ты хочешь оптимизировать если у тебя ничего нет ?

Пример выше дал, можно так:
CREATE TABLE goods_order (
_id INT NOT NULL default 0, /* id товара */
shopid INT NOT NULL default 0, /* id магазина */
cartid INT NOT NULL default 0, /* id корзины */
price INT NOT NULL default 0, /* цена товара за штуку */
numberOf INT NOT NULL default 0, /* количество товара с этим id */
PRIMARY KEY (_id))

А можно так:
CREATE TABLE ortho.goods_order (
_id int(11) NOT NULL AUTO_INCREMENT,
DATA json NOT NULL,
PRIMARY KEY (_id)
)

Где профит?
Добавление новых типов данных в состав заказа не потребуют изменения схемы СУБД
Обычный SELECT будет давать тебе готовый JSON, не надо будет собирать его по результатам запроса кодом.
Если правильно использовать на фронте - будет быстрее с большой долей вероятности. Такие вещи только нагрузочное тестирование покажет.
Опа, а это сильное колдунство. Спасибо, буду иметь в виду. Хотя и не везде подойдёт.

Даже в Вашей вышеприведённой схеме _id это идентификатор заказа. А как в json сделать запрос:

SELECT * FROM goods_order WHERE shopid=<идентификатор магазина>;

(который выведет ВСЕ товары в заказе, но только из ОДНОГО магазина).

Я и так старался минимизировать количество полей в таблицах. И, к слову говоря, сегодня уже нашёл косяк - взаимные перекрёстные ссылки между группой и групповой корзиной. Сейчас, по здравом размышлении решил вообще отказаться от корзин (таблиц carts и goods_cart), заменив из заказами (таблицами orders и goods_order) - структура идентична, добавится только четвёртое состояние заказа (создан; сейчас их три - оформлен, оплачен, исполнен). Более того - упрощается оформление заказа напрямую из корзины.
Psycho
27.08.2019
Как обычный запрос но с использованием функции JSON_EXTRACT() в качестве аргумента передается имя столбца таблицы где лежит JSON и ключ JSON, тебе возвращается значение. В данном примере такое себе решение, каждый JSON дергать, поля по которым будешь строить отборы лучше вытащить на уровень самой таблицы и индексы к ним прицепить. А в JSON условно-справочную информацию пихать.
Пойми нет тут _правильного_ решения, они все условно-правильные в зависимости от того как ты будешь это использовать.

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

А по теме - хрен редьки не слаще. От таблицы выполненных заказов никуда не денешься: нужно для той самой аналитики. Ну разве что написать скриптик, который будет бекапить и удалять старые заказы - например, полугодовой давности.
Разумеется, бекапить не на тот же сервер - место на нём не резиновое.
Psycho
27.08.2019
Почитал, кратко:
Таблица групп,таблица клиентов, таблица клиентов в группах.
Достаточно две. 1 и 3 в одной таблице.
По корзинам - это тупо ID корзины + ID пользователей, если пользователей > 1 она групповая. В отдельной таблице.
В таблице состава корзины ID заказа (мне кажется лучше триггером сделать BEFORE INSERT) ID корзины ссылка на товар+магазин, ссылка клиент, ссылка магазин+прайс (не надо два раза хранить цену), количество.

Фундаментально - в схеме нигде нет деления на "нужные" и "ненужные" записи.
Ты при удалении строки из корзины запись что ли будешь удалять ? Это плохой вариант.
Добавь булево для каждой строки и работай с ними.

Еще расписание у тебя как то загадочно реализовано, почитай про Нормальную форму Бойса - Кодда, и вообще про формы.
Psycho писал(а)
Почитал, кратко: <br> Таблица групп,таблица клиентов, таблица клиентов в группах.
Достаточно две. 1 и 3 в одной таблице.
В группе может быть больше одного клиента. Клиент может состоять больше, чем в одной группе.
Не знаю, может и имеет смысл в строке с перечислением ID клиентов, но ИМХО лучше держать просто таблицу из двух колонок: ID группы, ID клиента. Есть запись - клиент в группе, нет записи - клиента нет.
Psycho писал(а)
По корзинам - это тупо ID корзины + ID пользователей, если пользователей > 1 она групповая.
Не, я при создании пользователей дотумкал, что если корзина личная, то её ID совпадает с ID пользователя. И количество строк одинаково, и создаются они одновременно... Потому и хочу корзину вообще удалить и заменить заказом.
Psycho писал(а)
Ты при удалении строки из корзины запись что ли будешь удалять ? Это плохой вариант. Добавь булево для каждой строки и работай с ними.
Почему плохой? Нормальный вариант. А булево будет.

Фишка такая: когда клиент делает заказ - если все товары магазина в ней отмечены, корзина переоформляется в заказ (то есть заказ меняет статус с 0 на 1). Если отмечены не все товары - заказ всё равно меняет статус с 0 на 1, но при этом создаётся новый заказ со статусом 0 и неотмеченные товары перемещаются в него (то есть фактически в этих строках ID заказа меняется на новый).

А вот если клиент на самом деле удаляет товар из корзины, тут да - удаляется запись целиком. Но она всё равно состоит фактически из одних ссылок, то есть товар из ассортимента физически не удаляется.
Psycho писал(а)
Еще расписание у тебя как то загадочно реализовано, почитай про Нормальную форму Бойса - Кодда, и вообще про формы.
Спасибо, посмотрю. А так - там всё просто: 7 дней в неделе, начало и конец работы отмечаются в минутах, начиная с полуночи. То есть 480/60 = 8 часов утра по местному времени. 0 - выходной, 1- рабочий день. Ну и булево: требуется ли коррекция расписания с производственным календарём (официальные выходные могут не совпадать с календарными).
К слову, вот как раз для тарифов и расписаний вариант с JSON мне кажется идеальным.... Тем более, что эти данные можно хранить прямо в таблице магазинов (я так для краткости называю торговые точки - даже если они кафе или пиццерии)
Gavrosh
28.08.2019
Афраний писал(а)
Потому и хочу корзину вообще удалить и заменить заказом.

Не совсем понятно, для чего было изначально рассматривать её как отдельную сущность. Это не сущность и даже не атрибут, а одно из значений атрибута "Статус заказа".
Примеры значений :
"Корзина"
"Оплачен"
"Доставлен".
Во всех ключевых сущностях предусмотрите пару служебных полей NAVI_USER, NAVI_DATE формируемых триггером на insert|update. Потом спасибо себе скажете, когда будут разборки кто лазил в данные, когда и что там менял.
Psycho
28.08.2019
А я бы сделал отдельно, там соотношение будет где-то 1:20, далеко не все корзины станут заказами, хранить то не жалко, но мое мнение в том, что бизнес-данные должны быть именно бизнес-данными.
Gavrosh писал(а)
Не совсем понятно, для чего было изначально рассматривать её как отдельную сущность.
Отсутствие опыта. Проект придумал в голове и составлял сущности так, как видел.

Но с адресами - да, проблема актуальная.
В принципе, посоветовали мне тут воспользоваться Яндекс-Геокодером, но во-первых, меня смущают условия (25 тысяч бесплатных запросов в сутки), во-вторых нет смысла показывать адрес на карте, а в третьих, они прямо говорят: если надо для бизнеса - покупайте коммерческую лицензию. Я бы и купил, да больно цены кусаются.
Я ещё таблицу городов с таблицами запросов на добавление городов объединил.
Структура одинаковая, просто в запросе есть пара дополнительных полей: кто добавил город и статус рассмотрения заявки на добавление. Добавление ещё одного варианта статуса структуру не поломает.

В идеале, конечно, хотелось бы добавить сразу все города, но мне для каждого города нужно местное время и географические координаты.
Gavrosh
29.08.2019
Тут я ввел в заблуждение именами "аудиторских" полей. К географии это не имеет отношения.
Речь идёт о том чтобы оставлялись автоматические метки о том кто и когда правил данные в значимых таблицах. На таблице "Заказы", например, лучше иметь триггер:
CREATE OR REPLACE TRIGGER orders_au
BEFORE
INSERT OR UPDATE
ON orders
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
:new.navi_date := sysdate;
:new.navi_user := user;
END;
Спасибо, посмотрю. С триггерами ещё дела не имел.

Зато у меня в таблице городов поля lat и lng содержат широту и долготу. И для выбранного города есть кнопка "Показать на карте".

Думаю, или от этой функции отказаться, или при проверке адреса его тоже показать на карте. Просто нужны валидные адреса.
Psycho
30.08.2019
Интересную тему кстати затронул.
Учитывая, что система, пользователи и магазины имеют потенциально разные часовые пояса предвижу там много веселья по хранению даты и времени, учета перехода лето\зима по часовым поясам, etc.

Я в данном случае хранил бы везде в базе TIMESTAMP, и написал бы процедуру на возврат даты в нужном виде в зависимости от входных параметров пользователя\магазина\текущего положения\чего-то там еще.
Вот поэтому я для каждого города прописываю смещение в поле UTC. MSK=UTC+3

А перехода лето/зима сейчас вроде нет? Или я ошибаюсь?

Как я помню, у меня в дистрах спецом лежит патч для семёрки, исправляющий косяки со временем.
barsuk
30.08.2019
в принципе фсеравно на чем ты все делаешь, но скуль тебе нужно подтянуть
Вопрос был о минимизации нагрузки.

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

Ну и для того, чтобы скомпилированное выполнялось ещё быстрее, лучше вообще писать на Ассемблере :-)
barsuk
31.08.2019
неуч, учи скуль
зачем ассемблер, не останавливайся, пиши сразу в машинных кодах в семеричной системе
Неуч, учи ассемблер!
Ассемблер я знаю, да и машинные коды для меня секретом не являются.

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