Заключване на заявка

dakata__92

Super Moderator
Колеги, имам следния казус.
Имам една много тежка заявка, която трябва да извикам. Всичко е наред, тя си минава нормално. Искам, когато един потребител активира заявката за търсене, на всички останали потребители, които се опитат да пуснат същата заявка, да им изпиша, че трябва да изчакат вече пусната заявка от другия потребител да мине. Тоест не искам да се получи заключване на таблицата от едновременно пускане на 1 заявка да цикли от много хора. Мислех си да използвам Memcache и ако съществува стартиран рекуест да не позволявам на потребителите да правят нови заявки, докато тази не мине. Вие как бихте постъпили?
 
Никой ли няма идея освен с мемкеш, как по друг културен начин да реша този проблем?
 
Резултатът на тази заявка никак ли не може да се кешира? Или заявката - оптимизира? Колко време отнема?
 
Ако заявката е една и съща е лесно ще кешираш. Колко да е голяма тази база че да се чака много или е на дискоче 5400, или няма рам машината. Ако искаш просто да не се променя нищо а да има опашка.
https://stackoverflow.com/questions/49210653/waiting-for-mysql-database-query-complete-before-proceeding
https://codeburst.io/node-js-mysql-and-async-await-6fb25b01b628

Ако имаш памет apc https://www.php.net/apc_add
Може и с Memcached https://www.php.net/memcached
Може и на файлове https://pear.php.net/package/Cache https://pear.php.net/package/Cache_Lite

Всичко е според желанието и нуждите.
 
Колко е тежка тази заявка и в какво измерваш? Товар на процесора, заета памет?
Горе-долу колко време отнема трипа до базата данни?

Не може ли да се оптимизира заявката?

Това, което искаш да направиш е индикация за лош user experience. Щом това се получава, значи нещо не е наред, освен ако не е изискване към приложението.
Само не разбрах Memcache за какво ти е? Искаш да кешираш заявки или просто някъде да добавиш флаг, че е стартирана такава заявка. Ако е само за това, то и сесия ти стига да използваш.

Ако не е изискване, а само начин за замазване на положението, то се замислете за вертикално скалиране, или ако се налага хоризонтално.

В другата тема спомена, че имате репликация. Ако всичките сървъри не могат да се справят с това, значи или заявката иска сериозно оптимизиране, или сървърите ви искат ъпгрейд.
Няколко пъти си споменавал, че работите с много записи. Ако тези записи растат драстично, един и същи сетъп на базата данни не може да издържи вечно.
 
Revelation каза:
Колко е тежка тази заявка и в какво измерваш? Товар на процесора, заета памет?
Горе-долу колко време отнема трипа до базата данни?

Не може ли да се оптимизира заявката?

Това, което искаш да направиш е индикация за лош user experience. Щом това се получава, значи нещо не е наред, освен ако не е изискване към приложението.
Само не разбрах Memcache за какво ти е? Искаш да кешираш заявки или просто някъде да добавиш флаг, че е стартирана такава заявка. Ако е само за това, то и сесия ти стига да използваш.

Ако не е изискване, а само начин за замазване на положението, то се замислете за вертикално скалиране, или ако се налага хоризонтално.

В другата тема спомена, че имате репликация. Ако всичките сървъри не могат да се справят с това, значи или заявката иска сериозно оптимизиране, или сървърите ви искат ъпгрейд.
Няколко пъти си споменавал, че работите с много записи. Ако тези записи растат драстично, един и същи сетъп на базата данни не може да издържи вечно.
Тази заявка е за админ панел вече. Проблема, не е в това, че е тежка за сървърите, а в това, че таблицата постоянно бива попълвана. Говорим за голям дневен трафик и се налага да се прави справка какво постъпва на входа на системата. Желаем да избегнем заключване на таблицата заради пуснати няколко справки за голям период от време от съпорта. Заявката е откровено опростена:
Код:
SELECT column FROM table WHERE string LIKE '%text%' LIMIT 1
Самата заявка не е проблем за изпълнение от системата, проблема е в човешкия фактор. Ако в един момент 15 човека пуснат да цикли търсене на един от сървърите и в този момент има голя трафик има възможност да бъде локната таблицата. Не се е случвало но е превантивна мярка. Таблицата е важна и трябва да се внимава с нея!
Та по самия въпрос, продължава да ми се върти идеята с мемкеш. Не съм сигурен дали това е откровено добро решение.
 
muti каза:
Ако заявката е една и съща е лесно ще кешираш. Колко да е голяма тази база че да се чака много или е на дискоче 5400, или няма рам машината. Ако искаш просто да не се променя нищо а да има опашка.
https://stackoverflow.com/questions/49210653/waiting-for-mysql-database-query-complete-before-proceeding
https://codeburst.io/node-js-mysql-and-async-await-6fb25b01b628

Ако имаш памет apc https://www.php.net/apc_add
Може и с Memcached https://www.php.net/memcached
Може и на файлове https://pear.php.net/package/Cache https://pear.php.net/package/Cache_Lite

Всичко е според желанието и нуждите.
Сървърите не са проблемни нито от към памет, нито от към сървърна мощ. Просто искам когато един потребител пусне заявката да не позволявам на останалите да пускат заявка към същата таблица, докато тази не мине.
 
Всяко търсене го запивай в базата в някаква таблица със статус отворено, като приключи го маркираш като затворено.
Така по всяко време ще можеш от тази таблица да видиш колко отворени търсения има и да ги ограничиш.
 
Ако заявката ти е с like '%dasda%' не се учудвам, че локваш цялата таблица. Това е нашина за търсене в малки бази данни. Бързо, лесно и удобно. Строго ти препоръчвам да помислиш за full text search. Ето няколко линка :
https://www.w3resource.com/mysql/mysql-full-text-search-functions.php
https://makandracards.com/makandra/12813-performance-analysis-of-mysql-s-fulltext-indexes-and-like-queries-for-full-text-search
2705

Дори и да имаш индекси на самата таблица, няма да можеш да постигнеш подобрение. Защото индекса се изгражда от началото към края на полето, а с процентите при търсенето ти прескачаш началото и края в началото и става положение когато нямаш индекс.
Или имаш много потребители или това не е цялата заявка която си показал по-горе и тя минава за повече от секунда. В този случай, кеша няма да помогне, защото той иска не кара машианта да изпълнява заявката отново и отново докато се изпълнява вече. Явно отнема много време. Да тротълнеш можеш пак с мемкеш да записваш заявката преди да е започнала да се изпълнява и да я чистиш, след като е минала. Ако вече тази заявка я има - да даваш някаква грешка. Но в това нещо виждам адски много който могат да възникнат. Да - мемкеша може би ще е по-бърз от базата данни, но прихващането на грешка е доста тежка операция и ще натовариш процесора супер много и излишно. Ако базата данни и изпълнението на кода са на една машина - тогава забавяш всичко.

Ако можеш да минеш към full text search направи го. Работи доста по-добре от like в смисъла на качествени ресултати, по-бързо и ефикасно.

Не мога да си представя случай, в който искаш дадена заявка /селект/ да не бъде изпълнена много пъти едновременно.
Това което можеш да направиш е да я заключиш за четене, да изпълниш селекта, да я отключиш.
https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html
Код:
mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES
Примера който е даден в сайта, смятам, че точно това нещо искаш. Да я заключиш да не можеш да четеш, и след това да си я отключиш.
В този случай заявката, няма да мине, ще хвърли грешка която трябва да прихванеш при другите потребители.
 
index каза:

Всичко е така, но аз НЕ трябва да заключвам таблицата. Съгласен съм, че не е оптимално решение, но го направих с мемкеш. За запаметяване в базата, което предложи uphero, не си заслужава да го правя.

Код:
 if (!cache()->has($memcacheOptions['key'])) {
                    $itemsQuery = $this->getMemcache($sqlString, $memcacheOptions);
            } else {
                $itemsQuery[] = (object) [
                    'json' => 'Message to users'
            }
 

Горе