ugrás a tartalomhoz

Üzenetkezelő rendszer

iddqd · 2012. Aug. 28. (K), 16.27
Sziasztok!

Most olvastam a hasonló témát, én is ilyesmivel ügyködök és a véleményetekre, tapasztalatotokra lennék kíváncsi.
Szóval a cél egy oldalon belüli üzenetkezelő rendszer, php + mysql.

Amit tudnia kell a rendszernek:
Lényegében, van 3 csoport user - kliens - admin. User azoktól a kliensektől kapja meg az üzeneteket, akiket követ. ( + admin, de ő természetesen nincs feltételhez kötve, minden usernek küldhet )
User és kliens között N:M kapcsolat van.

Az én elképzelésem, ameddig jutottam:

1. Ábrázoltam a kapcsolatokat külön ( nem csak a levelezés miatt kell )
kapcsolatok tábla: user_id - kliens_id

2. Van egy táblám az üzeneteknek:
msg_id, sender_id, subject stb

Na most user megkapja a "kapcsolata" alapján a kért leveleket, ez idáig stimmel.
Szeretnék állapotot is tudni a levelekről pl olvasott -> új üzenet érkezést jelezni, vagy törölt -> a user törölhesse a levelet a "saját listájáról".

Ehhez azt gondolom kell készítenem még egy táblát:

3. üzenetek_állapota tábla:
user_id, msg_id, status ( olvasott/törölt )
Akkor születne rekord, ha a user megnyitotta a levelet. ( ?? )

Na itt kezd kicsit sántítani a dolog nekem... Vélemény?

Ekkor, az "új üzenet érkezett" funkciót, ( képzeljük el ezt most fb -sen, piros boríték stb, nem ez a cél csak valami hasonló, lényeg hogy valahogy szeretném majd használni ), megkapnám a két tábla különbségeként, illetve listázáskor a törölteket levonva. DE ez a kezelés nekem elég macerásnak tűnik...

Kicsit utána számolva, ( ez nem egy éles project, de feltételezve igazi működést ) mondjuk 5000 user nél és 500 kliens nél, ha átlagosan 1 kliens havi 3 üzenetet küld és 1 user átlagosan 10 kliens üzenetét olvassa, akkor üzenetek táblába havi kb 1500 rekord kerűl. Az állapot táblába 150 000. A két táblával számolni, keresni, műveleteket végrehajtani milyen terhelést jelent?
Jó lehet ez az irány? Esetleg máshogyan kellene megközelítenem?

Köszönök minden véleményt, kritikát, segítséget, tapasztalat megosztást!
Üdv!

Szerk.: Sorry srácok ezt lehet, hogy az adatbázisokhoz kellett volna, utólag is elnézést érte!
 
1

Üzenet

Poetro · 2012. Aug. 28. (K), 17.53
Az üzenetnek van címzettje is? Ha van címzettje, akkor csak egy lehet? Ha csak egy címzettje van, akkor a status az üzenethez tartozik. Ha egy üzenetnek több címzettje is lehet, akkor lehet jogosultsága az üzenetek_állapota táblának. 150e elem nem tűnik túl nagy számnak, megfelelő indexeléssel pár ms alatt lehet a keresés. Az, hogy neked mennyi olvasatlan üzeneted van, és mik azok elég egyszerűen ki lehet olvasni, és csak egyetlen JOIN szükséges. MySQL és más SQL motorok esetén általában a táblába beszúrás a költséges, nem az olvasás.
5

Lemaradtak a dolgok bocsánat.

iddqd · 2012. Aug. 29. (Sze), 10.22
Lemaradtak a dolgok bocsánat. A jelenlegi elgondolásom alapján, feladója van csak.
Az "N:M kapcsolattal" akartam utalni hogy 1 kliens -> több üzi -> több user olvashatja. Tehát mindenképp kell a üzenetek állapota tábla! ( ? )
User-kliens kapcsolat tábla alapján kérem 1 usernek azokat az üzeneteket, üzenetek táblából , amiknek szerepel az id -je user-kliens -nél. De szeretném megjeleníteni, hogy user kapott e új üzit, illetve törölheti a saját listájáról az üzenetet, ergo csinálnék egy állapot táblát.
A kérdésem az lenne hogy ez a logika/megoldás helyes-e, működőképes?!
Az egyiket megválaszoltátok, elvileg ezt az adatmennyiséget gond nélkül kezelhetem!
2

Pár dolgot nem értek

Pepita · 2012. Aug. 29. (Sze), 02.54
- ami nem ritkaság... :)
Lényegében, van 3 csoport user - kliens - admin. ...
- Egy adott felhasználó lehet user is és kliens is? Mert ha nem, akkor pl. válaszolni nem tud. Illetve akkor sem biztos, hogy tud, ha lehet egyszerre mindkét csoportban, mert az üzenet küldője pl. nem követi őt. Illetve mi az az N:M kapcsolat? (Asszem egy a válasz.) Ha ezeket kicsit megmagyaráznád, valószínűleg lenne 1-2 ötletem.

A 150000 rekord nem sok - mint Poetro is írta -, viszont ez ugye havi szinten van. Egy év múlva 12 x 150000, ..., szóval valamiféle karbantartás szükséges lesz időnként, pl. archiválás. Ezzel már az adatbázis tervezésekor érdemes foglalkozni.

U.i.: igen, adatbázisokhoz kellett volna. :)
6

Kihagytam 1-2 dolgot!

iddqd · 2012. Aug. 29. (Sze), 10.24
Bocs most nézem, hogy kihagytam 1-2 dolgot! Fáradt voltam már tegnap kissé... :)
Kihagytam pl: hogy az üzenet küldés egyirányú, csak kliens küldhet üzenetet usernek! Fordítva nincs üzenet! N:M kapcsolat = több-több kapcsolat, mindkét fajta egyedhez tetszőleges számú másik fajta egyed tartozik, arra akartam vele utalni, hogy user - kliens kapcsolatát mindenképp külön táblában kell ábrázolnom, nem így szokták hívni? Plusz kifelejtettem: természetesen userszám emelkedésével és/vagy kliens emelkedésével + idő, nő a rekordszám de persze lenne karbantartás, esetleg lejárata is bizonyos üzenteknek, ami után automatikusan törlődnek.
Szóval ahogy mondod nem feltétlenűl 12x150e egy évben.
3

Mysql-ben milliós

Kubi · 2012. Aug. 29. (Sze), 08.34
Mysql-ben milliós nagyságrendű rekordal nyugodtan dolgozhatsz, ha megfelelően van indexelve (kereséshez, rendezéshez) a táblád, join is faszán működne, ha jól joinolsz :)

Ha jól sejtem azt szeretnéd megoldani, hogy az admin a hozzá tartozó mondjuk 300 juzernek egyszerre küldjön üzenetet, csak egy usernek nem tud, bár még az is megoldható.

A fenti logikád erre teljesen fasza,

SELECT * FROM message s JOIN message_status ms ON (ms.msg_id = s.id AND ms.user_id = ?)
ORDER BY ms.status;

Így a joinod hatékony lesz, csak az adott usernek az üzeneteit kapod meg, remélem nem rontottam el így reggel az első kávém előtt :)

Fenti select query esetében a status-ra egy indexet tenni kell, hogy gyorsabb legyen a lekérdezés.
4

még annyit, hogy lehet a

Kubi · 2012. Aug. 29. (Sze), 08.40
még annyit, hogy lehet a másik irányból megfogva, jobb.

SELECT * FROM message_status ms JOIN message m ON (m.id = ms.msg_id) WHERE ms.user_id = ?

sőőőt, ez lesz a nyerő, sry, még csak most éledek.
7

Igen hasonlóan gondoltam én

iddqd · 2012. Aug. 29. (Sze), 14.24
Igen hasonlóan gondoltam én is! A query nem probléma, az érdekel hogy ésszerű e ez a terv így, alkalmas e a feladatra?! ( Tábla mennyiség, logika stb ilyesmi )
Nem csináltam még ilyesmit.

Szerk.: Én is az első kávé előtt voltam... :)
Nem egészen erre, de a lényege hasonló.
CSAK User kaphat üzenetet, azoktól a kliensektől, akitől ő szeretne. ( 1 kliens írhat több üzenetet és 1 user kaphat több klienstől üzenetet ) Admin üzenetét mindenki megkapja.
( bár ez még kérdés hogyan építsem be ha egy tábla van összesen az üziknek, meg kell különböztetnem admint valahogy, esetleg másik tábla - most ültem neki. )
Igen egy usernek így ebben a felállásban nem tudok küldeni de elvileg nincs is rá szükségem. ( max mail meglátjuk )
Az üzenetek állapotát így külön táblába kell tennem, nem tudom besuvasztani sehova. Két lehetséges értéket szántam neki olvasott( mondjuk '1' ) / törölt ( '2' ).
Ha user bejelentkezik szeretném neki jelezni hogy van nem olvasott üzenete, ezért kell értelem szerűen olvasott státusz. Ha pedig megnézi az üzeneteket a töröltek nélkül kell az eredmény. Ezt próbálom ezzel az adatbázis szisztémával megvalósítani.
8

Nem lesz ez így jó...

iddqd · 2012. Aug. 29. (Sze), 19.04
Nem volt ma túl sok időm foglalkozni a dologgal, de úgy érzem nem lesz ez így az igazi. Lesz itt bonyodalom úgy érzem a lekérdezéseknél!
Gyorsan átfutottam a dolgokat és ezzel a felállással csak azt lekérdezni pl bejelentkezéskor hogy van e olvasatlan üzenet úgy nézne ki hogy kapcsolatokból lekérdezem "követett" kliens_id -ket, ezekkel lekérdezem kliensek üzeneteit, majd ezt összevetem az üzenet státuszokkal és a státusztalan üzik lennének az újak, ha vannak. De ezt még hogy hogyan kapom azt nem tudom, kivonni nem lehet nem kompatibilisek az eredmény táblák, join -nal sem ezt az eredményt kapom. És ekkor még nem beszéltem a többi kezelésről.
Bár szanaszét volt ma a fejem, lehet hogy a megoldás itt van valahol előttem csak nem találom most. Mind1 holnap neki tudok ülni majd.
Addig is örömmel veszek véleményeket!
Köszönöm az eddigi segítséget is mindenkinek!
Üdv
9

túl bonyolítod

Kubi · 2012. Aug. 29. (Sze), 23.10
A követett "admin/kliens" lekérdezése felesleges.

A státusz táblában minden user-hez, aki kapott a leválből van egy bejegyzés, igaz?

Amikor az "admin" elküldi a levelet, akkor kell kikeresni azokat a usereket, akik meg kapják a levelet a beállítások szerint. Ez egy lekérdezés, kapsz egy user listát. Majd szépen összeállítasz egy nagy insert query-t, egyszerre akár 1000 elemet is beszúrhatsz, tapasztalat szerint 1milcsi rekord eltart kb fél percig, vagy addig se.

Beérkezett levelek lekérdezése meg csak annyi, hogy user_id = ? AND status = <olvasatlan> => 0.0001 sec :)
Az adminnak még az is megmondhatod, hogy hányan nézték már meg a levelet.

szólj ha rosszul látom.
11

Eredetileg nem akartam rögtön

iddqd · 2012. Aug. 30. (Cs), 10.18
Eredetileg nem akartam rögtön a kapott levélből egy rekordot, 'olvasatlant' nem akartam tárolni, csak akkor került volna bejegyzés a státusz táblába ha user benézett a postaládájába ( olvasott vagy törölt ), ha nincs róla státusz bejegyzés állapota csak olvasatlan lehet.
Ezért a bonyodalmam, de zsákutcának tűnik. Így ahogy írod könnyen le tudnám kérdezni, egyszerűen státusz szerint ez tiszta sor, csak így meg akkor azonnal minden userel fel kell vennem egy állapotot ugye, ezt el akartam kerülni ( bár gyakorlatilag ahogyan akartam az sem spórolós ) . Ez sem tűnik a legjobb megoldásnak. De ha máshogy nem megy ez még mindig maradhat.
10

Válaszidők

Pepita · 2012. Aug. 30. (Cs), 04.06
Nem akarok Kubival arról vitatkozni, mennyi rekord/JOIN/stb sok vagy kevés, ezek mindig és mindenhol igazak:

- Sok/kevés terhelés ill. idő elsősorban a vas és az adatbázismotor függvénye. Mivel előre sosem tudod az egyidejű látogatottságot, nem tudod, hogy egyszerre hány db erőforrásigénylésed lesz.

- Főleg fenti miatt, de egyébként is: erőforrással mindig érdemes "spórolni" (~optimalizálás), "legrosszabb esetben" villámgyors lesz a cucc. Persze ezt is okosan, nem a végletekig.

Kissé furcsállom ezt a fajta felállást.
Üzenetküldést (bármilyet) én inkább úgy tudok elképzelni, hogy a felhasználóknak vannak jogosultságaik (pl. tud üzenetet küldeni) és tartoznak 0-1-több felhasználói csoporthoz. Aki tud küldeni, az a megírt üzit tudja 1-több csoportnak küldeni. Itt a csoportokhoz rendelést a Júzerekre bíznám, a jogokat meg az adminra. (Végülis a "küldeni tudó" is lehet egy csoport, de akkor szoftveresen kell figyelni, hogy azt a Júzer ne választhassa magának.)
Ha valamelyik csoporthoz tartozik, akkor kapja és kész. Majd kiveszi magát a csoportból, ha nem kéri.
Az üzenetek táblában meg simán from_id, to_id, status, ...
Így is a küldés lesz a hosszabb, de az INSERT / UPDATE tudtommal minden motornál amúgyis jóval lassabb, mint a SELECT.

Ennek a megközelítésnek az előnye, hogy ugyanaz a Júzer könnyedén lehet küldő és fogadó is. Minden üzenet annyiszor van tárolva, ahányan kapják (ez rossz), de könnyedén lehet egyedileg kezelni a státuszt. Emiatt mondjuk lehet is szépíteni, hogy a tárgyat, üzenetet, feladót, stb. kiveszed másik táblába (vhogy úgy, ahogy csináltad).

És ez nem jelenti azt, hogy rossz lenne a te ötleted, ez csak egy másik.
12

Az első két pont miatt

iddqd · 2012. Aug. 30. (Cs), 18.19
Az első két pont miatt szeretném, a legmegfelelőbb megoldást megtalálni.
Összecsapni már összetudtam volna, azért nem kellet volna sokáig tökölnöm :)

Ráébresztettetek, hogy nem jó ez az irány, ahogy leírtam nem teljesen felel meg
a tényleges működésnek. Most nekikezdtem kicsit máshogy, majdnem meg is van, holnapra csiszolgatom még, indexelek, lemérem és majd megkérdezem még 1x, hogy mit szóltok! :D

Köszönöm az időtöket!

OFF: Pepita, te ilyenkor dolgozol, vagy ilyenkor érsz rá?! :D
13

Irány

Pepita · 2012. Aug. 31. (P), 02.37
Átgontoltad azt is, amit futólag vázoltam? Van egy olyan érzésem, hogy ha nem is az a pont jó megoldás, de az irány arrafelé van (jogok, csoportok, Júzerek).

OFF:
Pepita, te ilyenkor dolgozol, vagy ilyenkor érsz rá?!
Igen.

Na jó, mostanában minden második héten (éjjel) olyan dolgom van, ami mellett tudok / van időm WL-ezni. A másik héten viszont annál kevésbé. Ne irigykedjen senki: nem egy rózsás helyzet, nem is publikus.