Транзакции или скрипт?

146 отговора 0 прегледа
#1

Транзакции или скрипт?

База данни - MySQL 5.0.21
В една таблица постоянно се добавят записи.
Тези записи се обработват от хора - има php интерфейс.
Целта е агента да избере необработен ред, да го обработи и да върне отговора.
Проблемът - има случаи когато 2ма агенти взимат един и същи ред. Рядко ама става. И понеже скрипта записва кой кога какво взима (в друга таблица) се вижда че пичовете успяват да вземат същия ред с точност до секунда.
Правихме врътки - тоест скрипта дръпва реда за обработка и го маркира на следваща команда. Опитахме и update...
Сега планираме преход към InnoDB (от MyISAM).
Това е едния подход - да успеем да направим нещата с транзакции. Чуденката ми е - дали select може да блокира само един ред, така че следващ select да избере следващия ред (а не да чака първата транзакция да приключи).
Другия подход - ще си спретна едно допълнително скриптче което ще си слуша на някой порт, и ще връща наистина последователно каквото му искат. Сигурно ама не е елегантно.

Bеer? Mоre?
Плацебото
Отговор
в отговор на bira_more #2

Re: Транзакции или скрипт?

оплетено ми се вижда твоето описание

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

в смисъл първо записва че ред е взет и след това го взема
следващия първо гледа дали реда не е взет и ако е свободен резервира и взема

може да се сложи и код да избегне едновременна резервация на ред

този начин не зависи от базата и е за такива които предпочитат да пишат код

също може да прочетеш
[линк]



No pain, no gain

Редактирано от wiz на

Отговор
в отговор на bira_more #3

Re: Транзакции или скрипт?

заложи на неелегантния според теб метод. не знам какво не му харесваш. можеш да го смениш някой ден, когато му дойде приоритета и то ако изобщо се окаже, че другия метод е по-елегантен (въпрос на вкус).

hell storms, rush over the earth
bestial invasioooooooooooon
Отговор
в отговор на wiz #4

Re: Транзакции или скрипт?

Тъпото е че баш това парче го прави един друг колега. Мисля че е опитал подобен подход.
В смисъл - единия процес проверява, другия променя (щото вече е проверил), първия също променя - понеже не е било променено когато е проверявал - кофти.

Не смее да легне на changed rows (след update) щото ползвал persistent connection - и не е много ясно - на него, а на мен ич - какво ще стане.
Май ще си заложа на отделния скрипт - поне такива съм правил доста.

Bеer? Mоre?
Плацебото
Отговор
в отговор на bira_more #5

Re: Транзакции или скрипт?

ми като чета как пишеш оставам с впечатление че ти и твоя колега сте затрупани със задачи, нямате време да огледате картинката като цяло и е добре вашите шефове да почерпят някои да помогне

ето по подробно описание на функция която взема реда:
- проверява дали реда е записан като зает, ако не е -> записва че е зает и го взема
- след това чака малко и гледа дали е записан като зает повече от един път, ако е така гледа кои е резервирал първи и втория се отказва, тук се хваща ако двама са уцелили по едно и също време еднакъв ред, времето което се чака може да е малко че да не се забелязва от потребителите но да е достатъчно да избегне дублиране
- връща реда или грешка според това дали е първата или следваща резервация на реда



No pain, no gain

Редактирано от wiz на

Отговор
в отговор на wiz #6

Re: Транзакции или скрипт?

И това сме го мислили. Ама и то не ми харесва като решение.
Бачкаме по наследен код. Шефовете са на поне 10 000 км. И има времена - никакъв зор. Тогава тръгваме да оптимизираме - и изниква някакъв пожар. Ама пожар - за вчера. И след това - като нацвъкаме колкото можем какъв да е код, само и само нещо да стане - пак покой и пак чистене и оптимизации.
Картинката като цяло представлява купчини таблици - голяма част от които не се ползват, ама не смеем да трием щото знае ли човек. Към това добавяш още купчини php за веб, perl за AGI, промени в Астериск.
А бе веселба.

Bеer? Mоre?
Плацебото
Отговор
в отговор на bira_more #7

Re: Транзакции или скрипт?

ми това е начин на работа на много места, рано или късно се стига до там че нищо съществено не може да се добави понеже е голяма плетеница

както казваш има начини да се подредят нещата по добре ама не е лесно и струва пари

иначе не ми се вярва че ще намериш кои знае колко по добро решение от функцията която предлагам



No pain, no gain
Отговор
в отговор на bira_more #8

Re: Транзакции или скрипт?

колко са юзърите, които ще заявяват ред за промяна по него? 5, 20, 100, няколкостотин?

hell storms, rush over the earth
bestial invasioooooooooooon
Отговор
в отговор на bira_more #9

несериозно оправдание?

казано с други думи начина да ти хареса повече е вашите шефове да почерпят(някои като мен) и заедно с вас и тях да се подредят нещата с мисъл за напред

ама цената на такова решение е доста по голяма от текущите разходи които правят сега вашите шефове и сигурно не им се дава толкова, подобно тъпо отношение на парче като че ли е епидемия от глупост по фирмите

а и има много възможности проекта да се провали заради някоя добре звучаща почти безсмислена екстра и да завърши с несериозно оправдание като твоето

И това сме го мислили. Ама и то не ми харесва като решение.



No pain, no gain
Отговор
в отговор на ЛУД ПPЪЧ #10

Re: Транзакции или скрипт?

2 - 5 най-много от общо може би 20.

Bеer? Mоre?
Плацебото
Отговор
в отговор на wiz #11

Re: несериозно оправдание?

По някога ме чуват - та съм спестил някои "екстри".
Ама все пак са си шефове.
За цената - те си знаят. Аз ще опитам със serialize - и ако стане - добре, ако не стане - със екзекютив - там със сигурност ще стане.

Bеer? Mоre?
Плацебото
Отговор
в отговор на bira_more #12

Re: Транзакции или скрипт?

щом юзърите са малко и __ако__ ти се занимава да слагаш чалъми, и __ако__ имаш primary key от горе-долу прост вид (например autoincrement):

1. сложи таблиза с една колона с тип като тази на primary key от същинската таблица
2. сложи й unique key
3. когато юзъра иска да заяви ред за корекции, select-ваш (N+1) реда и 1 по 1 вкарваш ключа в новата таблица
4. първия, който влезе без duplicate key е бил незаявен и юзъра работи по него
5. като свърши работата, триеш от новата таблица (ако е заложено да трябва да се освободи реда за последваща редакция)

в т.3 числото N е максималното количество едновременно работещи юзъри и (N+1) ти гарантира, че в най-лошия случай последния селектиран запис ще бъде свободен. за 20 юзъра едва ли ще се усети някакво забавяне.

лично на мен повече ми допада да има нещо, което да раздава записи (идеята ти за скрипта), но може за вас да не е подходящо.

hell storms, rush over the earth
bestial invasioooooooooooon
Отговор
в отговор на bira_more #13

Re: несериозно оправдание?

ми начина които предожих също ще стане
не зависи от езика и базата и е опростен -> по-лесно може да се поддържа

кво не хареса в него?

май си поредния които пренебрегва опростените варианти и не разбира че имат съществено предимство в случай като вашия когато сте претрупани от задачи



No pain, no gain
Отговор
в отговор на bira_more #14

Re: Транзакции или скрипт?

Докторе ...

Най-чисто е с InnoDB не заради транзакциите а заради заключването по редове:

SELECT ... FOR UPDATE; и никой не може да пипне този ред докато не го пуснеш.

От друга страна това май не е достатъчно защото тогава следващата сесия ще чака търпеливо и накрая пак ще обработи същия ред втори път т.е. трябва или по някакъв начин да маркираш редовете като вече обработени или направо да ги местиш в друга таблица.

И в двата случая с InnoDB ще си гарантираш по-лесна работа.

Най-елементарния подход е ако можеш "обработката" да я вкараш в един единствен UPDATE

Тогава с WHERE правиш промяната само ако редът не е обработен. Остава въпроса как да върнеш на клиентската част какво си обработил аджеба, но това може да се реши с някаква уникална колонка. UUID() примерно, но пък нея можеш да я използваш и за проверка дали редът подлежи на обработка.

примерно:
ALTER ...

ADD COLUMN processed CHAR(36) NULL,
KEY(processed)

UPDATE x SET ......, processed = UUID() ... WHERE processed IS NULL;


Как ти се струва?

salle.online.bg/sig
Отговор
в отговор на salle #15

Re: Транзакции или скрипт?

SELECT ... FOR UPDATE
Това не го знаех - явно не съм чел достатъчно. Е никога не съм ползвал транзакции де - та до някъде е обяснимо.
Имаме поле подобно на предложеното от теб - UUID - та явно комбинацията от двете ще трябва да сработи.
Мерси много.

Bеer? Mоre?
Плацебото
Отговор
в отговор на wiz #16

Re: несериозно оправдание?

Точно защото не мисля че е опростен вариант. Опростен вариант е това което предлага salle, ама той си е майстор.
Шефовете - могат да измислят кой знае какво. А новата таблица си е нова таблица - а аз искам да намаля бройката на таблиците.
Пичовете които теглят реда са 2 групи. Днес има 1 от първата и 2 от втората, утре ще измислят 3 групи или дявол знае какво. И трябва да правим 2, 3 или дявол знае колко допълнителни таблици. И като забърша някоя дето не трябва, или ....

Bеer? Mоre?
Плацебото
Отговор
в отговор на bira_more #17

Re: несериозно оправдание?

ми сигурно от много задачи не забелязваш че това което предлагам е по прост вариант

не са необходими допълнителни таблици

нали вече има таблица в която се записва кои какво прави и може би в нея само трябва да добавиш още 1-2 колони: номер на заявка(или дата/час) и кои е текущия потребител, тези колони е по вероятно да ги има вече

още малко и ще поискаш да го направя безплатно че да те убедя че съм прав

Редактирано от wiz на

Отговор
в отговор на wiz #18

Re: несериозно оправдание?

1. Смятам че salle е много по напред с MySQL от кой да е друг в този форум. Можеш да погледнеш подписа му.
2. Интуицията ми подсказва да заложа на неговото предложение, още повече че и аз търсех нещо подобно.
В края на краищата - колегата ще реши, щото друг прави PHP интерфейсите. Аз го насочих към тази дискусия и толкоз.
От форумите а и от живота съм разбрал едно - даваш съвет а който иска да го следва.

Bеer? Mоre?
Плацебото
Отговор
в отговор на bira_more #19

Re: несериозно оправдание?

Смятам, че се предоверяваш на salle -- той работи по репликацията а не по db-enigine-а.

Това което предлага wiz ("проверява дали реда е записан като зает, ако не е -> записва че е зает и го взема") са пълни глупости ако двете стъпки не се случват в транзакция -- дори предполагам, че в момента е така и има проблеми.

Идеята е, че трябва да сериализирате резервирането на редове. Сериализирате = да го направите да се случва серийно, т.е. ако двама потребители са опитват да резервират ред (без значение дали е един и същ или различни) нека това не се случва едновременно, а да се изчакват. Всякакъм друг достъп до таблицата (справки, UPDATE-и) не ни бъркат и няма да ги trottle-ваме.

Нямаме транзакции заради MyISAM-а, обаче забелязвам че разполагаме LOCK-ове на ресурси, конкретно гледам LOCK TABLES tbl_name.

Значи правим си една dummy таблица за целта и резервиране на ред за редакция става по следния начин:
1. LOCK на dummy
2. Намираме "свободен" за редакция (SELECT @free_id = id ... WHERE ...)
3. Маркираме като резервиран за редакция (UPDATE ... WHERE id = @free_id)
4. Пускаме LOCK на dummy

LOCK-а ни гарантира, че двама потребители няма да се "разминат" между 2-ра и 3-та стъпка. Т.е. user A 2. -> user B 2. -> user B 3. -> user A 3. -> ouch.

Съществува голяма вероятност да не съм разбрал "заданието", но и без друго нямаше какво да правя...

cheers,
</wqw>

[линк]
Отговор
в отговор на wqw #20

хаха не си дочел какво съм писал

след реда които си прочел wiz ("проверява дали реда е записан като зает, ако не е -> записва че е зает и го взема")

има още един ред в които се проверява за едновременно резервиране

я пак прочети текста които съм писал


- проверява дали реда е записан като зает, ако не е -> записва че е зает и го взема
- след това чака малко и гледа дали е записан като зает повече от един път, ако е така гледа кои е резервирал първи и втория се отказва, тук се хваща ако двама са уцелили по едно и също време еднакъв ред, времето което се чака може да е малко че да не се забелязва от потребителите но да е достатъчно да избегне дублиране
- връща реда или грешка според това дали е първата или следваща резервация на реда


с твоя коментар тази тема почва да ми прилича на конкурс кои може да измисли най голяма глупост

и понеже съм в добро настроение ето ти и малко дефиниции да попрочетеш какво значи сериализация


Serialization is the process of taking an object and converting it to a format in which it can be transported across a network or persisted to a storage location.

Term Serialization
Definition Conversion of an object (instance) into a data stream of bytes.


[линк]
[линк]



No pain, no gain

Редактирано от wiz на

Отговор