Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: 3 вопроса по бд для 5к проекта

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Описание: LEFT JOIN и ISNULL, запрос инсерт с конкатенацией и on duplicate, memcahe
broshurkaplus
Отправлено: 18 Сентября, 2015 - 21:26:08
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




чето запутался уже, перестраиваю боевой проект где много count и с 5к хитов сильно тормозит, портал + доска объявлений
собственно

1
Выбрать записи из т1 и присоединить значение из т2 если они существуют или '0'

в t1 ключ автоинкремент , в t2 ключ varchar (в реале1, 1-125-3, 16-5243-128 итд)

t1
1 значениеAAA
2 значениеDDD
3 значениеXXX

t2
1 2

пишу

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT t1.col2, IFNULL (t2.col2, 0) AS zn FROM t1 LEFT JOIN t2 ON t1.id=t2.id


ожидаю
значениеAAA 2
значениеDDD 0
значениеXXX0

получаю
значениеAAA 1
значениеAAA 1
значениеAAA 2
значениеDDD 0
значениеXXX0

если нет ключа в t2 то выдаёт список, где col2 повторяется несколько раз
что может быть или как по другому запросить ?...



и немного теории
2
для получения агрегированных данных (сумм по рубрикам и категориям в разрезе регионов и тд) к нагруженной таблице (частый инсерт апдейт дел) думаю поставить триггер, который будет добавлять/обновлять в другую таблицу (t2 из предыдущ. вопроса) после вставки +1 к нужным строкам - один запрос инсерт с конкатенацией и on duplicate , вставка или обновление за раз всего строго 6 строк.
эта таблица, после полного набора вариантов ид (более 3млн как минимум) в итоге будет только обновляться и пользоваться на чтение
все для того, чтоб меньше использовать count на большом наборе данных

основное - сильно ли это будет нагружать бд (дергание триггером 6 строк по ид варчар) при постоянном чтении по ид?
какой альтернативный вариант организации может быть?



3
пользую memcahe для хранение результатов count запросов на больших данных, храню 1 минуту, +использую lock ключ на 50 сек, а пока идет первый конкурентный запрос отдаю старые данные.
(чтоб не делать count, а делать выборку - для этого и триггер из вопроса 2)
загоняю сразу готовый html под один ключ около 1500-3500 символов, а при выборке, разбиваю массив по разделителю и вывожу в разных блоках...

думаю что готовый html хранить лучше или как?
как проследить сколько у меня хранится значений в 1500-3500 символов, и как такой размер нагрузит мемкеш?

может можно как-то лучше реализовать алгоритм?
(нет никого в реале у кого можно было бы gjkexbnm консультации Недовольство, огорчение)

спасибо
 
 Top
lastdays
Отправлено: 19 Сентября, 2015 - 13:10:05
Post Id



Частый гость


Покинул форум
Сообщений всего: 220
Дата рег-ции: Март 2013  


Помог: 7 раз(а)




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

По моему поиск по varchar не лучший вариант.
Тем более с LEFT JOIN , и тем более с разными типами данных в запрашиваемых таблицах.

Проект очевидно старый.
Нужно найти эти "твердолобые" места с запросами.
EXPLAIN в том же phpmyadmin может с этим помочь, выполнив некоторые запросы в ручную, может не хватает банально ключа для поля.
5к юзеров не так и много.
 
 Top
broshurkaplus
Отправлено: 19 Сентября, 2015 - 17:50:40
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




lastdays пишет:
По этому использовать тоже нужно с умом

lastdays пишет:
поиск по varchar не лучший вариант


может вы выразите (и еще кто нибудь) мысли более конкретно в контексте вопросов и указанных цифр по пунктам?

(Отредактировано автором: 19 Сентября, 2015 - 17:51:26)

 
 Top
Мелкий Супермодератор
Отправлено: 19 Сентября, 2015 - 18:22:19
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




broshurkaplus пишет:
много count и с 5к хитов

Что это за величина? Укажите нормальные человеческие qps (раздельно r/w) и tps для субд, а так же rps в целом для бекэнда средние и пиковые.

broshurkaplus пишет:
если нет ключа в t2 то выдаёт список, где col2 повторяется несколько раз

Если в t2 нет такого значения, выдаётся 0.
А вот если есть - то выводится столько строк, сколько их есть в t2. Потому что join и никакой группировки.

broshurkaplus пишет:
для получения агрегированных данных

Один из двух возможных вариантов как разгрузить субд от постоянных count. Или кэшировать или дёргать триггером.

broshurkaplus пишет:
пользую memcahe для хранение результатов count запросов на больших данных, храню 1 минуту

Хорошо работающий кэш не использует вытеснение по таймауту, только по LRU. Обновляет при этом кеш тот, кто собственно и пишет.
Хорошо или плохо писать html в memcache - вопрос спорный. Главное, не мешайте в одном инстансе мемкеша мелкие и крупные куски, иначе начинаются проблемы с фрагментацией и неэффективным использованием памяти.


-----
PostgreSQL DBA
 
 Top
broshurkaplus
Отправлено: 19 Сентября, 2015 - 19:30:01
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




мелкий

дело в том, что в t2 может быть только одна соответствующая строка с двумя полями (ключ варчар и значение)
реально ключ для связи формируется динамически от пользовательских запросов, это условный пример ключ "1" => в т2
1-1
1
1-1256-12
выбираем ключ 1

?вроде как пробела не должно быть IFNULLтут(...


?я кеширую - можно подробней пример или как "дёргать триггером"



ставлю по таймауту тк за это время данные могут (99%)изменятся (в том то и сложность чтоб отдавать как можно более свежие данные , разгрузив бд).
:
добавили объявление - изменилась их сумма в регионе, городе, разделе, категории, рубрике.
это ключи в т2 изменяем значения +1 для ид: (регион, регион-город, регион-город-раздел,...)

в кеш ложу выборки - html 1500-3500 символов, в итоге получаю, пример:
запрос пользователя на главн стр, те для данной страны
отдаю html + html из мемкеша, разобрав в блоки шаблона по разделителю:
из кеша
сумму объявлений по регионам (из т2)
сумму объявлений по разделам (из т2)
итог расчета count сумму объявлений всего/покука/продажа/обмен/беспл атно в данном примере по стране
из скрипта
последние 10 объявлений

если перехожу в раздел => все тоже только для категории
если перехожу в регион => все тоже только для городов региона
если перехожу в город и раздел=> все тоже только для категорий этого раздела по этому городу

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

? может видите какой другой алгоритм

спасибо

(Отредактировано автором: 19 Сентября, 2015 - 19:30:37)

 
 Top
Мелкий Супермодератор
Отправлено: 19 Сентября, 2015 - 21:40:38
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




broshurkaplus пишет:
дело в том, что в t2 может быть только одна соответствующая строка с двумя полями (ключ варчар и значение)

Ваша СУБД с вами однозначно не согласна.

broshurkaplus пишет:
в том то и сложность чтоб отдавать как можно более свежие данные

А зачем? Если у вас реально на столько интенсивная запись, что минутный кеш является проблемой, значит, когда пользователь увидит страницу (именно увидит, а не сгенерирует сервер, т.е. через несколько секунд) это значение уже устареет.
Уж тем более для счётчика по региону это просто бесполезно.

broshurkaplus пишет:
или как "дёргать триггером"

То что сами описали в начальном сообщении.

broshurkaplus пишет:
поэтому и по таймауту тк данные постоянно меняются

Вы не объяснили, зачем вам время жизни записей в мемкеше. Данными вы и управляете, значит и кэшировать можете нормально событийно.
Создали объявление - отправили запрос в базу, проинкрементили соответствующие значения. Удалили - сделали декремент.

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


-----
PostgreSQL DBA
 
 Top
broshurkaplus
Отправлено: 19 Сентября, 2015 - 23:06:49
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




немного проясняется ситуация...

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

в итоге склоняюсь к такому алгоритму:
после создания/удаления объявления триггером на ней выполняем +1/-1 к соответствующим строкам (сейчас строк 6) таблице со счетчиками
+ постоянное чтение по ид без условия и сортировок
в принципе должно работать быстро

+прихожу к выводу, что возможно нужно выкинуть сумму по регионам, которая дергается всегда, что чуть разгрузит бд на 1/6 транзакции обновления как я понимаю

...опять встает вопрос в скорости работы:
1 но какие могут быть скрыты проблемы, ведь в итоге тут будет строк многократно больше чем самих данных (объявлений) ?
2 стоит триггер insert on duplicate, тк какие то рубрики в каких то городах вовсе не задействованы, таблица меньше, возрастает по мере вовлечения рубрик в городах - или стоит изначально забить все возможные варианты, но сразу неимоверно увеличить количество строк
3 в итоге уберем count, но как со скоростью инкрементирования и чтения?
 
 Top
Мелкий Супермодератор
Отправлено: 20 Сентября, 2015 - 00:06:36
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




broshurkaplus пишет:
ведь в итоге тут будет строк многократно больше чем самих данных (объявлений) ?

Вы издеваетесь, да?
Там что, на столько мелкая и незначительная табличка, что смехотворные 3 ляма записей - это многократно больше?

По IFNULL догадываюсь, что речь о mysql?
На запросах insert on duplicate key update можно время от времени ловить дедлоки. Поэтому лучше заполнить таблицу счётчиков целиком и делать только update. А, кстати, да, обновляйте записи всегда в одном и том же порядке. Дедлоки и просто апдейтами хватать можно запросто.

В чём проблема инкрементов? Конкурентность записи, конечно, неважная получится, быстро упрётся в блокировки строк.

И терзают нехорошие предчувствия, лучше уточню: там не сделана какая-нибудь великая глупость вроде myisam вместо storage engine?


-----
PostgreSQL DBA
 
 Top
broshurkaplus
Отправлено: 21 Сентября, 2015 - 09:57:53
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




так, mysql
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT region_by.`region_name`, region_by.`region_url`, IFNULL (sum_by.`sum_sum` , 0) AS `new_sum` FROM region_by LEFT JOIN sum_by ON region_by.`region_id`=sum_by.`sum_id` ORDER BY `region_name`

region_id значения (1,2,3,4,5,6)
sum_id (1, 1-1, 1-25-358, 2, 2-25 и тд)
если region_id==1 так оно отдает все строки где sum_id имеет 1
где подвох?


все InnoDB

данных для беларуси например - 500 000
а рубрик 1000 и городов (населенных пунктов) 23000, реально какая то деревня не пользует все 1000 рубрик, а то и вообще не учавствует поэтому и insert on duplicate key update, а если сразу забить, то уже 23 ляма (и это не все счетчики)

я поэтому и интересуюсь - как это можно организовать? а пока пользую то что есть.
чтоб и правильно, и хорошо, стараюсь внимательно вчитываться в каждое слово.
 
 Top
Мелкий Супермодератор
Отправлено: 21 Сентября, 2015 - 11:07:07
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




broshurkaplus пишет:
если region_id==1 так оно отдает все строки где sum_id имеет 1

Ну, совершенно очевидно так джойн и работает.

broshurkaplus пишет:
то уже 23 ляма

Для таблицы счётчиков? Фигня вопрос даже для тупого mysql.
Хотя у вас ведь профиль нагрузки другой. Дедлоки на on duplicate update хорошо ловятся на аггрегации событий по дням, а у вас insert - штука редкая, так что on duplicate должен работать удовлетворительно, да.
Правда, всё равно не догоняю, почему ключ символьный, а не пара интов. Рубрики явно отдельная таблица со своим сиквенсом, нас.пункты - очевидно, тоже.

Реальных данных маловато. Из аггрегации можно было бы выкинуть строки с количеством записей этак до 10, но это сильно усложнит код, так что нафиг. Пусть лучше будет писаться аггрегации побольше, но зато сильно проще в работе и сопровождении.


-----
PostgreSQL DBA
 
 Top
broshurkaplus
Отправлено: 21 Сентября, 2015 - 11:40:54
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




мыж пмшем
CODE (SQL):
скопировать код в буфер обмена
  1. ON region_by.`region_id`=sum_by.`sum_id`

а не like %1%
он сравнить не может изза типа чтоли
надо, чтобы отдавало строки где region_id==sum_id, те 1=1 отдавало, а 1=1-1 или 1=1-25-35 нет
как написать чтоб так?

решил что символьный проще, тк при чтении сразу вижу что отдавать, а если по колонке на регион и город и инт то нужно с сравнивать по двум столбцам и в where пользовать and несколько раз
полагаю что так быстрее
хотя можно б было и несколько + индекс множественный, но ведь where and and and как то не нравиться
моежек какое другой решение видите?

(Отредактировано автором: 21 Сентября, 2015 - 11:43:48)

 
 Top
Мелкий Супермодератор
Отправлено: 21 Сентября, 2015 - 12:28:06
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




Сделайте пример на каком-нибудь sqlfiddle

broshurkaplus пишет:
полагаю что так быстрее

Населённый пункт для конкретики с id 10546:
в случае инта: 4 байта, 1 команда процессора на сравнение. Вы ведь не на AVR какой-нибудь работаете, а как минимум на 32-битной системе, а то и на 64? К тому же можно FK повесить.
в случае varchar: 5 символов, это уже от 5 до 20 байт в зависимости от кодировки плюс один байт на длину строки. Поинтересуйтесь, сколько ассемблерных команд надо, чтобы сравнить две строки на равенство. Затем, в памяти varchar занимает всегда максимальный разрешённый для этого столбца объём. А поскольку в mysql primary key - это всегда b-tree, varchar будет вести себя как char и всегда занимать максимальный объём и на диске тоже.


-----
PostgreSQL DBA
 
 Top
broshurkaplus
Отправлено: 21 Сентября, 2015 - 23:17:55
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




спасибо, строку много дольше проверять.
в итоге переделал ближе к вашему совету и вообще удалил ид автоинкремент, чтоб on duplicate иды не жрал на всякий случй
для диска выгода получилаь не очевидна - 6 полей инт *4 байта =24, а в стлучае варчар максимум 12-100-1000-1000-6-25000 +1 =25 но 1-1-1-1-1-1 +1=12 даже чуть экономичней.
в where однако теперь 5 раз AND? чтоб получить счетчик для региона (ключи по столбцам 0|0|0|0|1ид_региона|0)
в итоге так сделал - ввезде инт + составной индекс уникальный
раздел|категория|рубрика|типто_вара|регион|город|сч_всего|сч_частных|сч_бизнсе|сч_бу|сч_новы|сч_покупка|сч_продаж|сч_обмен|сч_бесплптно
однако триггер получился не кислый и с условиями - чтобы реально задействовать все варианты - дергает 15 строк

хм... это допустимо / на сколько может быть плохо или критично 15 записей?
может и кеш пока отрезать, ведь выбор счетчика по полю с where должен очень быстро + ещё пару индексов сделать составных под запросы

чтото не очень нравится правка 15 строк + чтение, чтение...
 
 Top
Мелкий Супермодератор
Отправлено: 22 Сентября, 2015 - 11:06:15
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




broshurkaplus пишет:
для диска выгода получилаь не очевидна - 6 полей инт *4 байта =24, а в стлучае варчар максимум 12-100-1000-1000-6-25000 +1 =25

Как-то вы неправильно считаете.
Каждый инт в символьном представлении - это до 10 символов текста, итого 65 символов (от 66 до 196 байт в зависимости от кодировки).
А если 4млрд значений слишком много для задачи - то надо сравнивать с mediumint или даже smallint вместо инта.

broshurkaplus пишет:
но 1-1-1-1-1-1 +1=12 даже чуть экономичней.

В этом случае эта калькуляция не работает, как уже писал:
Мелкий пишет:
в памяти varchar занимает всегда максимальный разрешённый для этого столбца объём. А поскольку в mysql primary key - это всегда b-tree, varchar будет вести себя как char и всегда занимать максимальный объём и на диске тоже.


Я не уловил, как изначальные изменения 6 строк превратились в 15.
Нормально, плохо или критично - зависит от соотношения затраченных ресурсов к сэкономленным. Т.е. соотношения записи новых значений к чтению из таблицы счётчиков.


-----
PostgreSQL DBA
 
 Top
broshurkaplus
Отправлено: 22 Сентября, 2015 - 11:14:55
Post Id



Посетитель


Покинул форум
Сообщений всего: 354
Дата рег-ции: Янв. 2011  
Откуда: Пружаны Бресткая обл. Беларусь


Помог: 2 раз(а)




да я уже перечитал мануал...
10 раз переделывал уже - никак не приду к требуемому результату, кроме как через count, щас скрины прилеплю чтоб видно было, что надо
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« SQL и Архитектура БД »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB