- One mobilszolgáltatások
- Magisk
- iPhone topik
- Poco M3 - felújított állomás
- Honor Magic V2 - origami
- Xiaomi 12T Pro - kétszínű, mint a kétszázas
- Samsung Galaxy S24 Ultra - ha működik, ne változtass!
- Kikapcsolhatja az AirDropot az Apple az EU-ban
- 45 wattos vezeték nélküli töltés jön az új iPhone-ba
- Google Pixel topik
Új hozzászólás Aktív témák
-
Taci
addikt
válasz
martonx #5094 üzenetére
Sajnos semmin nem változtatott, ~300e rekordnál a lekérdezésed ~13 mp alatt dob csak eredményt.
Viszont a Profiling szerint a legtöbb időt a "Copying To Tmp Table On Disk" viszi el.
És amit korábban linkeltem magyarázat szerint rendesen indexelt tábláknál ez a lépés nem is kellene, hogy ott legyen:
"But generally speaking, the indexed sort would probably be chosen, if for no other reason, because it does not need to accumulate the entire result set in temporary storage before sorting and thus uses much less temporary storage."Szóval ebből gondolom, hogy talán az indexeléssel lehet baja. Csak azt nem találom, mi. Egy (a lekérdezésnél használatlan) mezőn kívül mind indexelve van. A rajzolást már elkezdtem, hátha a végére jutok valahol.
-
nyunyu
félisten
GROUP BY az aggregáló függvényekhez (min, max, avg, sum...) kell, az mondja meg, hogyan csoportosítsa az adatokat aggregálás előtt.
Utána felsorolt oszlopokból képez egyedi halmazokat, és az aggregátor függvény oszlopában annak a halmazra lefuttatott függvényértéket fogod visszakapni.
-
Taci
addikt
válasz
martonx #5092 üzenetére
Köszönöm, hogy ránéztél.
Nem Select *-ot fogok használni, viszont itt nincs annyi mező, hogy a query-t bonyolítsam vele, így az olvashatóság kedvéért ehhez a példához elégnek találtam.
A Group By-nak tényleg nem jártam alaposabban utána még - főleg azért nem, mert ahogy írtad is az okát, működött, így nem gondoltam, hogy baj van vele. Mindenképp alaposan utána járok most már, már amikor tegnap a hibát láttam, akkor felírtam a teendők közé.
Megfogadom a tábla- és mezőneves tanácsodat.
Nem item a tábla neve ("rendes" neve van), de a fenti (egyszerűsítő) törekvés miatt ebbe a példába elégnek találtam.
Sajnos igen, ez a db fiddle-teszt nem elég arra, hogy itt és ennyi adattal kiütközzön a hiba úgy, mint sok adattal nálam.
De köszönöm szépen az ötletet is, és hogy ránéztél.
-
martonx
veterán
Észrevételeim:
1. Select *-ot el kellene felejteni, és ki kellene írni azokat mezőket amiket ki szeretnél listázni.
2. Group By-nál szépen leírja, hogy mi a baja: bele kell venni a többi listázandó mezőt is (érdemes utána járnod, hogy mi is az a group by, mysql, mariadb specialitás, hogy a példádban szereplő szintaktikailag helytelen group by egyáltalán futni tud bizonyos helyezetekben).
3. Önszopatás a táblák mezőit a táblanévvel kezdődően elnevezni. Ha van egy táblád, aminek categories a neve, akkor annak id, és name mezői legyenek, ne pedig category_id, category_name.
4. Nekem ez 4 ms alatt lefut, bár nyilván több szemszögből sem lehet összehasonlítani a te adataiddal (eltérő adat mennyiség, és MySql vs MariaDB, localhostos erős géped, vs. valami ingyenes osztott hosting a dbfiddle alatt).
SELECT DISTINCT *
FROM items AS i
JOIN items_categories AS ic
ON i.item_id = ic.item_id
JOIN categories AS c
ON c.category_id = ic.category_id
AND c.category_id NOT IN (1,3,13,7,20)
WHERE i.item_id NOT IN (117,132,145,209,211)
ORDER BY i.item_date DESC5. Az Item nevű tábláktól idegrángást kapok. Légyszi nevezzük már el normálisan a táblákat. Jó, hogy nem fiszfasz, meg izé nevű tábláid vannak fiszfasz_izé nevű kapcsolótáblákkal. Aztán amikor 2 év múlva ránézel, te se fogod érteni, hogy mit is akartál az egyes táblákkal leképezni.
-
Taci
addikt
válasz
martonx #5083 üzenetére
Sikerült feltöltenem, bár nem túl sok adattal: db-fiddle
(Fel akartam tölteni ~300e rekorddal, de nem hagyta, így nem akartam az időt húzni, hogy megtaláljam, hol a határ.)Eredetileg ezt a lekérdezést írtam bele (Group By-jal és Distinct nélkül):
SELECT *
FROM items AS i
JOIN items_categories AS ic
ON i.item_id = ic.item_id
JOIN categories AS c
ON c.category_id = ic.category_id
WHERE
c.category_id NOT IN (1,3,13,7,20)
AND
i.item_id NOT IN (117,132,145,209,211)
GROUP BY i.item_id
ORDER BY i.item_date DESC LIMIT 4
Viszont erre ezt a hibát dobta:
Query Error: Error: ER_WRONG_FIELD_WITH_GROUP: Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.ic.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by -
nyunyu
félisten
válasz
martonx #5083 üzenetére
Korábban írta, hogy MariaDBt használ, azt meg nem támogatja az SQLFiddle.
Múltkor próbáltam felrakni a gépemre a MariaDBt, de már az is gondot okozott, hogy találjak Win7 x64-en elinduló verziót, asszem a 10.3.30-ig kellett visszamennem.
Utána meg szívtam a mellécsomagolt HeidiSQL IDEvel *, aminek a működése eléggé az agyamra ment, meg az Oracle hibaüzeneteinél is semmitmondóbb hibaüzenetektől ** is a falra másztam, amikor valami szintaktikai hiba volt, vagy éppen Oracle kompatibilis módban lévő MariaDBnek nem tetszett a kód.
Kb. fél nap google után inkább feladtam, hogy az Oracle alatt hibátlanul működő példámat átírjam MariaDBre.*: Rég dolgoztam ennyire használhatatlan IDEvel, szerintem még az SQL Server 2000-ét is alulmúlja. (2005-től jött helyette a Visual Studio stílusú SQL Server Management Studio)
**: pl. a lemaradt egy vessző hibaüzenet végére odamásol sortörések nélkül 5 sor kódot, amiből minden látszik, kivéve az, hogy melyik sor végéről maradt le.
Ennyire hülye még az Oracle SQL Developer se szokott lenni, pedig az sem a szívem csücske. -
martonx
veterán
Nem tennél fel ide DB sémát, és adatokat? DB Fiddle - SQL Database Playground (db-fiddle.com)
Mert így leginkább csak magaddal tudsz társalogni. -
Taci
addikt
Ezt a "gyorstalpalót" értelmeztem most, hogy mégis mi-miért történik a lekérdezésben, hogyan kapcsolódnak ide az indexek, és hogy min csúszhatott el a dolog.
Azt hiszem, nekiülök "rajzolni", hogy lássam, hogyan működik a lekérdezésem, és hogy hogyan lehetne "optimálisan kérdezni". Lehet, máshogy kell indexelnem.
Rajzolok, aztán remélem, rájövök. -
Taci
addikt
A category_id-ra szükségem van, nem szedhetem ki. (De amúgy a teszt kedvéért kivettem, és semmi sem változott, se a sebesség, se a distinct nem hozta a kívánt eredményt.)
Annyit találtam, hogy ha használom a GROUP BY-t is, akkor a megfelelő eredményeket kapom, és valamelyest gyorsul a lekérdezés is. (És DISTINCT-tel vagy anélkül is ugyanazt a (jó) eredményt adja, szóval így a DISTINCT talán nem is kell.)
select p.*
from product p
join product_category pc1
on pc1.product_id = p.id
join category c1
on c1.id = pc1.category_id
where c1.name in ('sárga', 'piros', 'kék')
group by p.id
order by p.date desc;
Így a korábbi ~20 mp helyett már megvan ~9 mp alatt.
És az explain-je is sokkal jobban néz ki:
De a 9 mp még mindig szörnyű.
Merre tovább?
Vagy ez nem is a jó út?
Az adatbázis szerkezete a hibás?
Vagy a lekérdezés?Jelenleg nyitott vagyok a teljes adatbázisszerkezet átalakítására is. Egyszer már megcsináltam a javaslatotokra, megcsinálom megint, ha kell. Csak működjön végre.
Mindenesetre keresgélek még, hátha találok ilyen hasznos dolgot, mint a group by. Bár néztem már annyi mindent, millió stackoverflow-bejegyzést...
-
nyunyu
félisten
nekem az kellene, hogy a feed_id-kra legyen vonatkoztatva, tehát a képernyőfotós példában a 100111 csak egyszer szerepeljen.
Ha kiveszed a lekérdezésből a category_id-t, akkor minden feed_id csak egyszer fog szerepelni.
DISTINCT mindig a lekérdezésben szereplő összes oszlopra nézi az egyediséget!
-
Taci
addikt
válasz
bambano #5077 üzenetére
Alapból a my.ini-ben ez volt:
innodb_buffer_pool_size = 16MEzt most kicseréltem ennek a tartalmára:
my-innodb-heavy-4G.ini
innodb_buffer_pool_size = 2GÍgy a lekérdezés első futtatása ugyanúgy ~20mp-ig tartott, viszont amikor újra futtattam, már csak 0.01-ig.
Szóval ennél a lekérdezésnél a memória bővítése valóban segített, viszont, csak addig, amíg pont ugyanezt a lekérdezést futtatom, mert így memóriából tudja újra felhasználni. Amint akár egy feltételt is módosítok, újra 20mp várakozás, memóriába töltés. Aztán megint változtatok, megint várakozás. És ez csak 1 felhasználó, nem 10e-100e.Szóval sajnos nem ez a jó megoldás, de azért köszönöm a tippet.
------
@martonx: Az a legelső ajánlásaitok egyike volt, azóta indexelve van. Írtam is 3 hozzászólással korábban, hogy indexelt a feed_date.
Az EXPLAIN-eknél látszik, hogy hiába indexelt, mégis, ha van DISTINCT és ORDER BY is, akkor átnéz és rendez 410e rekordot lekérdezésenként, ezért tart 20 mp-ig...
Ha csak az ORDER BY-t használom, akkor 0,01 mp:
Ha csak a DISTINCT-et használom, akkor is 0,01 mp:
------
És ha van mindkettő, DISTINCT és ORDER BY is, akkor nem a jó logika mentén alkalmazza a DISTINCT-et, mert ez a találat (a LIMIT 4-gyel):
Tehát így a rekordok valóban különbözőek, viszont ezt ugye a JOIN-os nagy egészre nézi. És ebben benne van az általatok javasolt plusz tábla, amibe ki lettek szedve a kategóriák, hogy ha egy bejegyzéshez több kategória is tartozik, akkor az mind külön rekord legyen. És ezzel így összefűzve a DISTINCT valóban jó eredményt ad - csak rossz logika szerint:
nekem az kellene, hogy a feed_id-kra legyen vonatkoztatva, tehát a képernyőfotós példában a 100111 csak egyszer szerepeljen. -
Taci
addikt
Sajnos kb. pont ugyanez a kód (illetve a saját kiegészítéseddel ugyanez), amit írtál (és ami sztanozs tanácsára ki lett egészítve DISTINCT-tel), ez fut le eszméletlen lassan.
Bemásolom, hogy ne kelljen visszakeresni, és kiegészítem a DISTINCT-tel:
select distinct p.*
from product p
join product_category pc1
on pc1.product_id = p.id
join category c1
on c1.id = pc1.category_id
where c1.name in ('sárga', 'piros', 'kék')
order by p.date desc;
Ha benne van együtt a DISTINCT és az ORDER BY is, akkor ~20 mp, ha csak az egyik, akkor 0,05 mp a futási idő.
Plusz a DISTINCT nem is működik (úgy, ahogy elvárnánk), mert ha a product_category táblában egy id-hoz több category_id is van (és van, mert ezért lett ez a tábla létrehozva), akkor annyiszor listázza a product-ból az id-t. (Pedig pont ezért lenne használva, hogy egy id-t csak egyszer listázzon.)
A profiling opciót bekapcsolva ezt látom, ami "fura":
- Copying To Tmp Table On Disk: 18.9 s
- Sorting Result: 1 s
Tehát csak ez a 2 lépés 19.9 másodpercbe kerül, ha van DISTINCT és ORDER BY is.Ha csak az ORDER BY van, akkor:
- nincs Copying To Tmp Table On Disk lépés
- Sorting Result: 6 µsHa csak a DISTINCT van, akkor:
- Copying To Tmp Table: 2.8 ms
- nincs Sorting Result lépésAhogy utána olvastam, azt írják, hogy a DISTINCT és az ORDER BY is sorba rendez, és nem szeretik egymást. Azt is írják, hogy ha az egyiket használom, akkor a másikat valószínűleg nem kell. De hát ez itt nem igaz, mert a DISTINCT azért kell, hogy 1 id csak egyszer jelenjen meg (ami amúgy most sajnos nem igaz, ahogy feljebb írtam is), az ORDER BY meg azért, mert időrendi sorrendben van szükségem a találatokra.
Nagyon nem tudom, merre tovább. Követtem a tanácsaitokat, megcsináltam és átírtam mindent, ahogy javasoltátok, (amit köszönök ez úton is), de sajnos valami még nem kerek, és magamtól nem találok megoldást rá.
Higgyétek el, ég az arcom, hogy ennyiszer kell írnom, és segítségért kuncsorognom - nem jókedvemből teszem. Felajánlottam, hogy fizetek is a szaktanácsadásért és a segítségért, csak végre haladhassak, mert már 1 hónapja egy helyben veszteglek - de sehonnan nem kapok segítséget, sehol egy szakember.
-
Taci
addikt
Nagyon bénának és kapkodósnak érzem magam, pedig nem vagyok (kapkodós).
De ahogy most újra lefuttattam a lekérdezést (JOIN, amiben ott van az ORDER BY) is, láttam, hogy hiába van benne az elején a DISTINCT, a 4 találatból 3-nak ugyanaz a feed_id-ja.
Aztán fogtam, kiszedtem a DISTINCT-et (az ORDER BY ugyanúgy benne maradt), és a korábbi 19 mp-es lekérdezésből hirtelen 0.0615 mp-es lett... ugyanazzal az eredménnyel...
-
Taci
addikt
válasz
martonx #5067 üzenetére
Megvan a "bűnös": az ORDER BY.
SELECT DISTINCT *
FROM feeds AS f
JOIN feed_item_categories AS fic
ON f.feed_id = fic.feed_id
JOIN categories AS c
ON c.category_id = fic.category_id
WHERE
c.category_id NOT IN (1,3,13,7,20)
AND
f.feed_id NOT IN (101,456,3566,32345,56432,223444,344456)
ORDER BY f.feed_date DESC LIMIT 4
Ha benne van: Showing rows 0 - 3 (4 total, Query took 19.2113 seconds.)
Ha nincs benne: Showing rows 0 - 3 (4 total, Query took 0.0541 seconds.)Pedig indexelt a feed_date.
Amikor explain-nel megkérdezem, mi történik, ezt mondja:
table: f
type: index
possible_keys: PRIMARY
key: feed_date
rows: 298917
Extra: Using where; Using index; Using temporary; Using f...A "régi" lekérdezést miért nem lassítja be az ORDER BY?
SELECT * FROM feeds
WHERE
(feed_category NOT LIKE '%cat1%'
OR feed_category NOT LIKE '%cat2%'
OR feed_category NOT LIKE '%cat3%'
OR feed_category NOT LIKE '%cat4%')
ORDER BY feed_date DESC LIMIT 4
(Nem pont ugyanazt csinálja, mint a felső, csak azért másoltam be, hogy meglegyen, melyik a "régi".)
0.3591 seconds
Egyértelműen látszik, mennyivel gyorsabb a JOIN-os megoldás, de az a baj, hogy, hogy kell az ORDER BY - vagy legalábbis az lenne a fontos, hogy a leszűkített (WHERE) rekordlista teljes tartalmát időrendileg csökkenő sorrendben kell visszaadnom, négyesével.
Ezért csináltam úgy már eredetileg is, hogy megvan a feltételek alkalmazása (WHERE), aztán a találati lista rendezése (ORDER BY), aztán az első 4 listázása.
Aztán következő lekérdezésnél ugyanígy, csak a már korábban kilistázott elemek kizárása (id NOT IN...).Tudnátok tanácsot adni, kérlek?
-
Apollo17hu
őstag
Sziasztok! MSSQL-ben hogy tudom kiszurni azokat a rekordokat, amelyek kirxkraxokat tartalmaznak egy mezoben? Tehat a mezob n levo ekezetes karakterek helyett ilyen tokomtudja karakterkeszlet karakterei jelennek meg.
Probaltam regexp kifejezessel (azAZ), de ugy ertelmezi, mintha ezek a speci karakterek is az abece reszei lennenek. Nincs vmi egyszeru tisztito fuggveny erre? -
Taci
addikt
Megcsináltam mindent, amit javasoltatok, pont úgy, ahogy javasoltátok. Készen és beállítva az új táblák, rendben a kapcsolatok az indexek, és a rekordszám is feltornázva 500e fölé (a kategória-elem kapcsolatok száma 800e körül).
És így a javasolt a JOIN-os lekérdezés ideje: 25 másodperc...
A régi, pazarló LIKE-os lekérdezés ideje: 0.3 másodperc (egy picit javítva a LIKE-os módon már csak 0.01 másodperc)...Nem értem.
Csak "érdekességként" írtam ide (bár nekem bosszúság), már találtam valakit, aki remote-ban tud segíteni - bár ő is pont ugyanezt a JOIN-os módszert mondta, miután átnézne a tábláimat.
-
DeFranco
nagyúr
Sziasztok!
Van egy pivotolt lekérdezésem ami érdekes módon rossz, hiányos eredményt ad, az összegek sem "nagyösszesenben" sem az egyes részösszegekben nem stimmelnek. A kereszttábla fejei teljeskörűek, minden lehetséges értéket megadtam a
FOR
-nál:SELECT * FROM
(
(
SELECT
VALTOZO1,
VALTOZO2,
OSSZEG
FROM
TABLA_A
)
UNION
(
SELECT
VALTOZO1,
VALTOZO2,
OSSZEG
FROM
TABLA_B
)
)
PIVOT
(
SUM(OSSZEG)
FOR VALTOZO1 IN ('V_X','V_Y','V_Z','V_Q','V_W')
) PV1Ha ugyanezt lekérem
SELECT * FROM
(
(
SELECT
VALTOZO1,
VALTOZO2,
OSSZEG
FROM
TABLA_A
)
UNION
(
SELECT
VALTOZO1,
VALTOZO2,
OSSZEG
FROM
TABLA_B
)
)kóddal és magam összesítem, az eredmény helyes, pivottal nem.
Mi lehet a hiba, hol kezdenétek keresni?
-
nyunyu
félisten
Sokszorozás:
- Végigmész egy kurzorral a termék táblán, megjegyzed az eredeti adatait.
- kiosztasz neki egy új azonosítót
- beszúrsz egy új termék rekordot az eredeti adataival, csak id helyére az újat írod
- leválogatod a termék_kategoria táblából az eredeti terméked kategória értékeit
- beszúrod a termék_kategóriába az új termék_id, régi_kategória_id párosokat
- tetszés szerint ismétled-- sokszorozás
declare
regi_id number;
regi_name varchar2(100);
uj_id number;
i number;
cursor cur is
select p.id,
p.name
from product p
where instr(p.name,'_') = 0;
begin
open cur;
loop
fetch cur into regi_id, regi_name;
exit when cur%NOTFOUND;
for i in 1..1000
loop
uj_id := product_seq.nextval;
insert into product (id, name)
values (uj_id, regi_name || '_' || to_char(i));
insert into product_category (id, product_id, category_id)
select product_category_seq.nextval,
uj_id,
pc.category_id
from product_category pc
where pc.product_id = regi_id;
end loop;
end loop;
close cur;
end;Próbáltam SQLFiddlében összerakni a múltkori gyümölcsös példámat, de valamiért nem tetszik neki a szintaxis.
Hús-vér Oracle alatt persze simán legenerál 1000 új példányt minden termékből.
Ha a DB kezelőd automatikusan inkrementálja az id mezőt (kb. mindenki, kivéve Oracle
), akkor a for ciklus belsejében először beszúrod az új termék példányt, aztán leselectálod az id-jét az uj_id változóba, és úgy használod a termék_kategória beszúrásnál.
Pl. SQL Serveren valahogy így
...
while @i <= 1000
begin
insert into product (name)
values (regi_name || '_' || convert(varchar(10),i));
select p.id
into @uj_id
from product p
where p.name = regi_name || '_' || convert(varchar(10),i));
insert into product_category (product_id, category_id)
select
@uj_id,
pc.category_id
from product_category pc
where pc.product_id = regi_id;
set @i = @i +1;
end;
..(Még jó, hogy mindenki másképp írja a szabvány SQLen felüli részt.)
-
Taci
addikt
Megcsináltam így, működik is szépen, aktívak az indexelések is.
Viszont így már nem tudom ugye duplikálni a rekordokat, mert a másik táblában (ahol a rekordokhoz tartozó kategóriák vannak tárolva) már nem lehet olyan könnyen.
Szóval most egyelőre 159 rekord van.És amiért most írok:
Összehasonlításként futtatom a régi lekérdezést (LIKE '%category%'
stb.) és az új lekérdezést (JOIN
).És az a régi:
- egyrészt dupla olyan gyors (sőt, 0.0112 vs 0.0266 seconds),
- másrészt az Explain szerint csak a szükséges 4 rekordot ellenőrzi/használja (rows: 4) az indexelés miatt (a 159 helyett).Hogy van ez akkor?
A sebesség talán most még az alacsony rekord szám miatt lehet, később, sokkal több elemnél ez talán majd fordul?
Viszont Ti is azt írtátok, és én is azt találtam, hogy ha a LIKE operátor %sztring formában van használva, akkor a teljes táblát használja.
Itt akkor rows: 4 helyett nem rows: 159-nek kellene lennie?Bocsánat a sok kérdésért, de ha már így alakult, hogy saját kezüleg kell csinálnom, szeretném érteni a miérteket. És köszönöm, ha válaszoltok, tanácsot adtok.
(És továbbra is szívesen fizetnék a segítségért, a mostani struktúra átnézéséért, módosítására javaslatért, tanácsokért stb., csak hogy biztos lehessek az erős és stabil alapban.)Köszönöm.
-
Taci
addikt
Sikerült egy úgy-ahogy rendszert összeraknom, megcsináltam a táblát, feltöltöttem ugyanúgy, ahogy otthon is tenném, minden ugyanaz, kivéve, hogy most csak 20 elemet raktam bele, hogy tudjam kézzel szerkeszteni az ajánlott új táblákat is, és ne menjen rá túl sok időm.
Kész mind a három tábla, mondom akkor indexelem a dátum mezőjét (ahogy otthon is tettem), és lekérdezem EXPLAIN-nel, hogy jól dolgozik-e, elsőre csak az alap lekérdezéssel, hogy legyen összehasonlítási alapom:
EXPLAIN SELECT * FROM table ORDER BY date DESC LIMIT 4
Az otthoni rendszerben ez visszaadta, hogy
rows: 4, type: index.
Most azonban hiába ott van az indexelés (phpMyAdmin-ban egyértelműen látszik több formában is), ez a visszatérési érték:rows: 20, type: all.
Tehát nem indexelt semmit.
Próbáltam kézzel is (CREATE INDEX table_date_ix ON table(date)
), illetve grafikus felületen a megfelelő kapcsolóval. De ugyanaz az eredmény.Mi lehet ennek az oka? Túl kevés a 20 elem az indexeléshez? (Otthon 500e rekord volt a táblában, itt most csak 20.)
1. update:
Kíváncsiságból "felduplikáltam" kb. 100e rekordig, és most márrows: 4, type: index.
Ezek szerint a 20 kevés volt? Mennyi a "minimum limit"? Kézzel kell egyelőre dolgoznom, szóval nem mennék nagyon túl a minimumon, ha nem muszáj (és ha van ilyen, persze).2. update:
Visszatöröltem 20 rekordig, és most még mindig van indexelés...rows: 1, type: index.
Ezt nem értem.
Itt azon kívül, hogy hogyan és miért lett hirtelen indexelés ugyanannyi elemre, azon kívül még azt nem értem, a rows értéke miért csak 1, amikor a lekérdezés (explain nélkül) 4 rekordot ad vissza. A rows: 1 pedig ugye azt jelenti, hogy 1 rekordot vizsgált át.
Hogyan ad vissza 4 rekordot, ha csak 1-et vizsgált át?El tudnátok magyarázni, kérlek?
Köszi.
-
nyunyu
félisten
Nem karbantartható.
Ahányszor jönne egy új kategória, annyiszor felvennél kézzel egy új oszlopot a táblába, és megupdatelnéd az összes rekordot 0 értékkel?
Plusz az összes lekérdezést átírnád, hogy az új oszlopot is figyelje?Külön kategória táblában akárhány kategória elfér, csak egy új rekordot kell beszúrni, aztán annak az ID-ját hozzárendelni a termékhez.
Nem jár adatszerkezet és kód módosítással! -
Taci
addikt
(Mivel egyelőre még nem tudom kipróbálni a megoldást, így csak agyban tudok a témán "dolgozni", és az jutott eszembe, hogy) mi lenne, ha a ~30 kategóriának csinálnék egyszerűen mezőket a jelenlegi táblában? Lenne category1, category2 stb. nevű mező, értékként 0, ha a rekordhoz nem tartozik, 1, ha igen.
Így nem kellene LIKE-ot sem használni már, az eredeti lekérdezésSELECT * FROM table
WHERE channel_id
IN ('id1','id2','id3','id4')
AND
(category LIKE '%category1%'
OR category LIKE '%category2%'
OR category LIKE '%category3%'
OR category LIKE '%category4%'
OR category LIKE '%category5%'
OR category LIKE '%category6%')
AND
(category NOT LIKE '%category7%'
AND category NOT LIKE '%category8%'
AND category NOT LIKE '%category9%')
ORDER BY date DESC LIMIT 4
nézhetne ki így is:
SELECT * FROM table
WHERE channel_id
IN ('id1','id2','id3','id4')
AND
(category7 = 0
AND category8 = 0
AND category9 = 0)
ORDER BY date DESC LIMIT 4
(Mert most látom csak, hogy feleslegesen szűrtem arra is, hogy milyen kategóriákat listázzon, ha egyszer már ott van az is, hogy miket NE, és csak 2 állása van (vagy benne van, vagy nincs)).
Ez lenne olyan hatékony, mint a 3 táblás JOIN-olás? Vagy még hatékonyabb, esetleg kevésbé?
(Most kíváncsi lennék, az EXPLAIN erre mit mondana.) -
Taci
addikt
Nagyon szépen köszönöm a tanácsokat, segítséget, a részletes példákat! Lesz mit átnéznem, értelmeznem és kipróbálnom.
Eljöttem pihenni/nyaralni 3 hétre, szóval lassabban tudok csak reagálni, és egyelőre "vasam" sincs még ezeket a tippeket kipróbálni sem, de szerzek valamit, és ha nem bánjátok, utána kérdezek még.
Nem webshop-motort fejlesztek, azt csak a Te példád miatt vittem tovább (product). RSS feed-ekből szedem ki az adatokat (cím, rövid tartalom, kép, link, illetve kategória), majd ezek az adatok mennek adatbázisba. Itt kerül képbe a kategória, mert van, hogy 1-1 feed elemhez több kategória is tartozik (előre definiáltak), és a jelenlegi megoldásomat ("category1,category2,category3" stb.) kell átírnom az általatok javasoltra, külön táblákba kiszervezve.
Illetve majd később szeretném a (valódi) lájkolást és kommentelést implementálni, lehet, azt is akkor legalább elő kellene majd készítenem
Köszönöm a sok segítséget, és az időt, amit erre fordítottál! És persze mindenki másnak is a tanácsokat, segítséget.
-
nyunyu
félisten
És ha jól értem, ugye azt írod, hogy csináljak egy product_category táblát, amibe úgy kerülnének bele a rekordok, hogy ha a fő táblámban (product) mondjuk van 2 millió rekord, és mindegyikhez tartozik 2-4 (átlagban 3) kategória (category). Akkor e szerint a product_category táblában jelen állás szerint 6 millió rekord lenne.
Nem ez a lényeg, hanem az, hogy a kategória táblád párszáz, ezer rekordos lesz csak.
Ezen a string műveletek időigénye még nem tragikus, gyorsan le tudja kérdezni kategórianevekhez tartozó ID-t.
Aztán abból már könnyen joinolja a többmilliós product_category táblát (ha tettél indexet a category_id-re), így hamar megvan a product_id, ami meg szintén külső kulcs, a product tábla elsődleges kulcsára mutat, ami megint csak indexelt, aztán máris megvannak a megfelelő termék rekordjaid.Feltételezem, hogy valami webshop motort hegesztesz, ahol a vevő a termék kategóriára is tudna szabadszövegesen keresni, ezért kell a kategória névre string illesztés.
-
nyunyu
félisten
N:M kapcsolatnak pont az a lényege, hogy külön-külön lekérdezhető mindegyik variációja.
Teszemazt van egy product táblád:
id name
1 alma
2 körte
3 banán
4 szilva
5 narancsvan egy categoryd:
id name
1 piros
2 sárga
3 zöld
4 kék
5 narancssárgaEzeket összerendelő product_category táblád:
product_id category_id
1 1
1 2
1 3
2 2
3 2
4 4
5 1
5 5Ha erre ráuszítod az előző querymet c.name like '%sár%'-ral, akkor ki fogja neked listázni az almát, körtét, banánt, narancsot, mert azok SÁRga vagy narancsSÁRga kategóriásak.
Ha azt akarod kérdezni, hogy melyik az a termék, amiből van sárga és piros is, akkor kétszer kell a product_category-t és a categoryt joinolni, és azokat ANDdal kérdezni:
select p.*
from product p
join product_category pc1
on pc1.product_id = p.id
join category c1
on c1.id = pc1.category_id
join product_category pc2
on pc2.product_id = p.id
join category c2
on c2.id = pc2.category_id
where c1.name = 'sárga' and c2.name = 'piros'
order by p.date desc;Ez már csak az almát találná meg.
Ha ezt írnád:
where c.name = 'sárga'
or c.name = 'piros'
or c.name = 'kék'
vagy az ezzel ekvivalenswhere c.name in ('sárga','piros','kék')
feltételt, akkor az összes sárga vagy piros vagy kék gyümölcs lejönne (alma, körte, banán, szilva)
Narancs nem, mert itt kategórianévre teljes egyezés a feltétel! -
martonx
veterán
"És ha jól értem, ugye azt írod, hogy csináljak egy product_category táblát, amibe úgy kerülnének bele a rekordok, hogy ha a fő táblámban (product) mondjuk van 2 millió rekord, és mindegyikhez tartozik 2-4 (átlagban 3) kategória (category). Akkor e szerint a product_category táblában jelen állás szerint 6 millió rekord lenne."
Ez azért tud gyors lenni, mert ezek mind Foreign Key-ek, azaz indexeltek. Itt tenném még hozzá, hogy sokkal tisztább érzés lenne Kategória ID-re szűrni Name helyett.
-
Taci
addikt
Most (utazás után, de még pár hétig nem otthon) volt egy kis időm jobban átolvasni és értelmezni, amit a 3 tábláról írtál. Teljesen jól érthető, köszönöm. Pár részlet még nem világos benne, de azoknak utánajárok.
Illetve 1 dolgot mégis kérdeznék a kódoddal kapcsolatban:
where c.name like '%akármi%'
Ha úgy csinálom, ahogy mondod, és ha 1 terméknek 3 kategória, és így 3 külön rekord a product_category-ban, akkor itt nem kellene már LIKE-ot használnom sem, hiszen rekordonként csak 1 kategória lenne. Szóval ez akkor lehetne inkább:where c.name = 'akármi'
, nem?
(Több kategóriára szűrésnél meg valami ilyemi:where c.name = 'akármi'
or c.name = 'akármi1'
or c.name = 'akármi2'
Javítsatok ki, ha tévedek, kérlek.)És ha jól értem, ugye azt írod, hogy csináljak egy product_category táblát, amibe úgy kerülnének bele a rekordok, hogy ha a fő táblámban (product) mondjuk van 2 millió rekord, és mindegyikhez tartozik 2-4 (átlagban 3) kategória (category). Akkor e szerint a product_category táblában jelen állás szerint 6 millió rekord lenne.
Ez tényleg gyorsabb, mint a 2 milliós? Bár gondolom, erre is írta tm5 a redundanciát (ha nem, kérlek írd meg, mire).
Meg hát ugye azt is írtátok, hogy LIKE-nál az egész adatbázist átnézi, nem számít az indexelés és semmi, szóval az mindenképp lassú.Na ezt nem kis idő lesz így átírnom. Mielőtt nekikezdek: ezt az utat javasoljátok akkor?
- Külön tábla a kategóriáknak.
- Külön tábla a termékek és kategóriák kapcsolatának.
- Lekérdezés előtt (már ahol aktív a kategóriára való szűrés) JOIN.Köszönöm.
-
Taci
addikt
Azt használom, amit a DesktopServer feltelepített nekem: MariaDB. Az alap beállításon van, nem néztem még rá a konfigurációjára. (De utánanézek, hol és hogyan lehet.)
Amit ajánlottatok, külön táblát létrehozni a kategóriáknak, azt egyelőre nem tudom, hogyan kell megcsinálnom, ennek is utánanézek. Illetve akkor lehet, hogy más mezőket is "ki kell majd szerveznem".
Szóval örülnék egy szaki-ajánlásnak.
-
nyunyu
félisten
DB teljesítményhez két dolog szükséges: sok RAM, meg sok, gyors diszk.
Több procimagot is meghálálja, de arra nem annyira érzékeny, mint a kevés memóriára.Tényleg, nem valami ingyenes DB licenszet használsz, ami 1 magra és 1GB RAMra van korlátozva?
(Pl. Oracle XE, SQL Server Express) -
Taci
addikt
Köszönöm a tanácsot.
Igazából már azt gondoltam, készen vagyok, mehet élesben a weblap (és vele az adatbázis), csak eszembe jutott, megnézem, hogyan viselkedik majd x év adatfelhalmozódása után. És mint kiderült, nem jól...
Szóval tényleg át kell alakítanom, mert így nem lesz jó hosszú távon, és most még bármit csinálhatok vele, bárhogy alakíthatom, mert még csak tesztfázisban van (bár már 1-2 hét múlva küldtem volna bevetésre). Viszont igazad van, ennek tényleg újra neki kell ülni. De sajnos úgy látszik, egyedül én ehhez kevés vagyok. (Így is csodálom, hogy saját erőből (plusz a Ti segítségetek itt, plusz Stackoverflow, plusz W3Schools stb.) fel tudtam ezt építeni, elég sok ez (HTML, CSS, JS, PHP, SQL) egy embernek (nekem legalábbis), úgy, hogy még működjön is).
Szóval talán segítséget kellene kérnem (fizetőst, egy hozzáértőt pár óra szaktanácsadásra), hogy az alapok stabilak legyenek.
Mert hát ahogy írtad is, ilyen csepegtetett infókból nem fog összeállni a kép, és amúgy sem veletek akarnám megoldatni a felmerült problémákat.Ha esetleg tudtok ilyen szolgáltatást, akár itt, akár privátban jelezzétek, kérlek. (Elképzelésem szerint) óradíjban, megmutatom, hogy működik az oldal, ezt hogyan szolgálja ki jelenleg az adatbázis, ő pedig elmondja, mi és miért nem jó, javítjuk, teszteljük, és örülünk.
Mert logikázhatok én itt egyedül (a Ti segítégetekkel, amit ezúton is köszönök), de ha rossz a logikám, amiből indul az egész, akkor csak az időt húzom a semmire.
Viszont azt amúgy továbbra sem értem, hogy az alap lekérdezéssel miért ilyen piszok lassú, ha egyszer már indexelve is van, és LIKE és kategóriák a közelben sincsenek.
-
nyunyu
félisten
Jaj, itt már a relációs adatmodell alapjai is hiányoznak.
Ahogy tm5 írja, ki kéne tenni a kategóriákat egy külön táblába, amiben van egy category_id, és egy name mező.
Mivel ez pártíz-száz különböző értéket fog tartalmazni, ezen akár még a lájk is működhetne gyorsan, nem fájna annyira, mint egy nagyonnagy táblán.Mivel egy termékhez több kategóriát is szeretnél tárolni, illetve egy kategóriába több termék is eshet, így N:M reláció lesz a termék és a kategória között.
Ennek leképezése úgy történik, hogy csinálsz egy termék_kategória táblát, amibe beleteszed a termék azonosítóját, és a kategória azonosítóját.
Ahány kategóriába tartozik, annyiszor veszed fel ide a terméket, mindig a következő kategória azonosítójával.Lekérdezéskor meg joinolod az id-k mentén a három táblát, valahogy így:
select p.*
from product p
join product_category pc
on pc.product_id = p.id
join category c
on c.id = pc.category_id
where c.name like '%akármi%'
order by p.date desc; -
tm5
tag
Szerintem le kellene ülni és összeszedni, hogy mik az elvárások és az alapján tervezni egy adatbázist, mert most minden posztodban kiderül valami újabb dolog.
A category oszlopot inkább kiraknám egy külön táblába, mondjuk úgy, hogy ha van egy category szótárod (cat_id, cat_name) akkor lenne egy un. junction táblád (tabla_id, cat_id)
és akkor cat_id alapján gyorsan tudnál keresni. Ez esetben lehetne az IN operátort is használni. Kerüljük a redundanciát ha lehet. Egy Microsoft SQL-es MVP már 15 éve azt írta, hogy egy rendes 3. normálformájú adatbázis sokkal jobban teljesít, mint egy redundanciával teli.Én amúgy szeretek kompozit indexek helyett külön indexet használni leggyakrabban keresett oszlopokra. Esetleg megpróbálhatod ezt is.
-
Taci
addikt
Köszönöm a sok és részletes választ, illetve a tippeket!
Nem csak a
LIKE
-os lekérdezésekre ad vissza nagyon lassan választ, de az "alapra" is:SELECT * FROM table ORDER BY date DESC LIMIT 4
Ezért "nem látom, hogy működne" az indexelés, mert se "alap" lekérdezésnél, se kibővítettnél nem gyorsult semmit. Mit tudok még átnézni, változtatni, ellenőrizni? Lehet, csak a lokál szerver "miatt" ilyen lassú? Mert ha más nem, az alap lekérdezésre már jól kellene (gyors válasszal) működnie.----------
(A jelenlegi felépítés szerint) muszáj vagyok LIKE-ot használni:
A kategóriákra szűrök így. Mert jelenleg ha category1, category3 és category4-be tartozik egy elem, az most úgy van letárolva, hogy a category mező tartalma a rekordhoz:"category1,category3,category4"
De a user category1 és category4-re szűr rá, akkor (jelenleg) nem tudom máshogy, mint
AND
(category LIKE '%category1%'
OR category LIKE '%category4%')Rengeteg féle kategória van (30+), így ez lehet egy elég hosszú sztring is, ezért nem is nagyon tudom, hogyan tudnám máshogy megcsinálni.
De ha van tipped, szívesen veszem.Vagy esetleg ezt is lehetne
IN
-nel? Csak nekem úgy kell az eredmény, ha cat1 és cat4-re szűr, akkor mutassa, ha vagy az egyikben, vagy a másikban van (vagy mindkettőben, nyilván). De az IN-nél meg inkább AND az operátor, nem OR.
Tehát aWHERE category IN ('category1', 'category2')
nem jó eredményt adna vissza, nem?Köszönöm.
-
nyunyu
félisten
A probléma leginkább azzal van, hogy szótöredékre próbálsz keresni
like '%valami%'
, emiatt nem nagyon tudja hatékonyan használni a category_id-re tett indexet.Azért egy próbát megérhet egy (channel_id, category_id) összetett index, hátha segít valamit.
Ha szó elejére keresnél
like 'valami%'
, akkor könnyen meg tudná mondani az indexből, hogy melyik rekordok kellhetnek. -
nyunyu
félisten
Indexet elég egyszer építeni, utána automatikusan karbantartja a DB, amíg el nem dobod a táblát.
Index karbantartás miatti insert, update időtöbblet sokkal kisebb, mint amit a selecteknél nyersz.
Sőt, sokmillió rekordos DBből törléskor baromi lassú tud lenni, ha a wherenél megadott feltételeket nem tudja legalább részlegesen kiértékelni valamelyik index használatával.
Olyankor gyorsabb, ha létrehozol egy indexet (pár perc alatt megvan!), majd a nagy mennyiségű adat törlése után eldobod az indexet. -
nyunyu
félisten
Categoryt hiába indexálod, fészbúk operátor miatt mindig full table search lesz az eredmény...
Ha nem muszáj, ne nyomd a lájkot.
Nem tudom, melyik a gyakrabb a táblából olvasásnál, channel_id-re szűrés vagy a dátum szerinti rendezés, attól függően lehetne összetett indexet is használni, pl.:
CREATE INDEX table_ix1 ON table(channel_id, date);
Gyakrabban használt oszlopot tedd előre az indexben.Egy táblából olvasáshoz egyszerre csak egy indexet szoktak használni a DB kezelők, így hiába tennél minden oszlopra külön-külön, jobban jársz pár jól megválasztott összetett indexszel.
-
Taci
addikt
Bocsánat a sok posztért, de ebben a témában minden dolog új nekem, és szükségem van segítségre vagy megerősítésre.
Most pl. ebben:
Rátaláltam azEXPLAIN
-re. Így most látom, hogy arows
értéke 4 (type: index), tehát működik az indexelés, mert nem olvassa be mind a ~500e rekordot, hogy dátum szerint sorba állítsa.
Még akkor is 4 arows
értékeEXPLAIN
mellett, ha a korábban írt hosszú-hosszú lekérdezést indítom (OR, AND, LIKE, NOT, %%). Szóval ez "papíron" nagyon jól néz ki most.Viszont ha ez már így elvileg működik, miért olyan dög lassú még mindig magán az oldalon? 10x gyorsabb, ha az eredeti 7500 rekordot rakja sorba indexelés nélkül, mintha ezt az 500e-t indexelve.
Hol és mit kellene még megnéznem?
-
Taci
addikt
Közben pár dolgot még megtaláltam:
A konzolban (phpMyAdmin) a táblát kibontva az indexek alatt ott van a létrehozott index.
Aztán ha rákattintok ("Indexek"), akkor a megfelelő mező mellett látok egy szürke kulcsot, szóval létre lett hozva.
Illetve alul látom a tulajdonságait is:
Egyedi: Nem
Csomagolt: Nem
Számosság: 7597 (a PRIMARY-nak ezzel szemben ~500e. Esetleg ez a szám mutatja majd, hol jár az indexelés?) (De most töröltem az indexet, és újra létrehoztam. És most 7341-et ír... Nem értem.)
Nulla: Igen (?) -
Taci
addikt
Illetve még egy kérdésem lenne:
Indexeltem elvileg, aztán a duplikálással felvittem 500e körülre a rekordok számát.
Viszont ugyanolyan lassú még mindig.- Most akkor nem vártam eleget, idő kell az indexeléshez, és csak később lesz gyorsabb?
- Vagy az indexelés csak az aktuálisan létező elemekre vonatkozik, a jövőbeniekre nem, ezért mondjuk minden új rekord felvétele után újra indexelni kellene?
Ezt mondjuk most meg is válaszolom magamnak, mert újra futtattam az indexelős parancsot, és azt írja, nem lehet, duplikált kulcsazonosító.
- Nyomon tudom követni valahol vagy valahogy az indexelés állapotát? Azt írják, hogy a user nem látja, de valahol biztos jegyezve van.(Kérlek, ha lehet, az előző kérdéseket is próbáljátok már megválaszolni.)
Köszönöm.
-
Taci
addikt
Köszönöm a tippet.
Ezt a leírást találtam róla: [link]
Note: Updating a table with indexes takes more time than updating a table without (because the indexes also need an update). So, only create indexes on columns that will be frequently searched against.
Van ilyen lekérdezésem is:
SELECT * FROM table
WHERE channel_id
IN ('id1','id2','id3','id4')
AND
(category LIKE '%category1%'
OR category LIKE '%category2%'
OR category LIKE '%category3%'
OR category LIKE '%category4%'
OR category LIKE '%category5%'
OR category LIKE '%category6%')
AND
(category NOT LIKE '%category7%'
AND category NOT LIKE '%category8%'
AND category NOT LIKE '%category9%')
ORDER BY date DESC LIMIT 4
Ez alapján akkor ezeket a mezőket (channel_id, category) is indexelni kellene, mert végülis ugyanolyan gyakran vannak használva?
Látok a link alatt olyat is, hogy lehet indexet mezők kombinációjára is beállítani. A fenti példám alapján hogy lenne jobb? Index külön a mezőkre? Index ezek kombinációjára? Vagy is-is?És ezt a CREATE INDEX-et csak egyszer kell mezőnként futtatni, és onnan "rendben van"? Azért kérdezem, mert próbálok mindent automatizálni, hogy ne kelljen figyelni rá, ha nem muszáj, és ha ez is olyan, amit többször kell meghívni, akkor erre is figyelnem kell.
Bocsánat a sok kérdésért és értetlenkedésért, csak erről most hallok először, és fontosnak tűnik, nem szeretnék hibázni vele.
Köszönöm.
-
nyunyu
félisten
Próbálj meg indexet tenni a date mezőre.
CREATE INDEX table_date_ix ON table(date);
Akkor nem próbálja meg felolvasni az egész táblát a memóriába 4 rekord kedvéért, hanem csak az indexet tölti be, és az alapján választja ki a következő négyet.
Sokmillió rekordos táblákat nem móka index nélkül használni...
-
Taci
addikt
És meg is van az eredmény... 2 millióig tudtam felvinni a duplikálást. Most pedig az apache logban ezeket találom:
Nincs elegendő memória-erőforrás a parancs feldolgozásához.
Érvénytelen cím hozzáférésére tett kísérlet.
Fatal error: Out of memory (allocated 467664896) (tried to allocate 16384 bytes)És nem is tölt be semmit az adatbázisból.
Jelenleg ez csak egy desktop server, csak tesztelni.
De előfordulhat ilyen hiba a szolgáltatónál is?
Az én kódomban van a hiba?Amúgy nem egy nagy lekérdezés volt, csupán ennyi:
SELECT * FROM table ORDER BY date DESC LIMIT 4
És erre dobta a fenti hibákat.
Nekem kell javítani/változtatni valamit, vagy ez a DesktopServer korlátjai miatt van, és a normál szerveren (szolgáltató) ezzel nem lesz gond?
Köszi.
Upd.: 1 milliónál is ugyanez a baja. De 500ezernél már lassan, de végzi a dolgát.
-
Taci
addikt
Sziasztok!
Van rá mód esetleg, hogy valahogy (egyszerűen) sokszorosítsam az adatbázisom (az egyik tábla) tartalmát?
Jelenleg kb. 4e elem van benne, és szeretném megnézni, hogyan viselkedne mondjuk 400e vagy 4 millió elemnél. Mennyire lassulna be stb.
Meg lehet ezt oldani egyszerűen? (Nem kell a tábla semmire, teszt fázisban van csak, törlöm, és újra feltöltöm, ha az kell majd.)
Köszi.
-
tm5
tag
válasz
RoyalFlush #5029 üzenetére
SELECT TRUNC(RENDELES_DATUM, 'MONTH') HONAP, COUNT(*) DARAB
FROM TABLA
WHERE TERMEK = 'Termék2'
GROUP BY TRUNC(RENDELES_DATUM, 'MONTH')
ORDER BY 1 DESC -
RoyalFlush
őstag
Sziasztok!
A segítségeteket szeretném kérni egy lekérdezés összeállításában.
Oracle PL/SQL.
RENDELES_DATUM DATE
TERMEK VARCHAR2(255)RENDELES_DATUM TERMEK
2020-06-15 Termék1
2020-06-14 Termék1
2020-06-14 Termék2
2020-06-14 Termék2
2020-05-25 Termék1
2020-05-25 Termék1
2020-05-10 Termék2
2020-04-05 Termék2
2020-04-01 Termék1
...Azt kellene kimutatni havi bontásban egy időszak intervallumra vonatkozóan, hogy a termék1-ből és a termék 2-ből együttesen mennyit rendeltek.
Példa az outputra:
2020-06 4 db
2020-05 3 db
2020-04 2 db
2020-03 15 db
2020-02 34 db
2020-01 22 db
...Előre is köszönöm szépen!
-
#68216320
törölt tag
válasz
martonx #5023 üzenetére
Sorry, nem válasz akart lenni.
Sziasztok.
Kicsit off a téma, de nem teljesen.
Tudtok olyan free web api url-t, ami az EB meccsek eredményeit folyamatosan visszaadja mondjuk json vagy valami hasonló formátumban? Szeretnék egy parser-t csinálni rá, hogy saját db-ben tudjam használni ezeket. -
martonx
veterán
Én mint C# fejlesztő, aki mellette sokat SQL-ezett is régen, ezzel nem értek egyet.
Csak szimplán nem kell hülyének lenni, és el kell mélyedni az egyes nyelvekben.
Az SQL totálisan más logikai megközelítést igényel, mint egy normális programnyelv. De mindkettő megérthető, megtanulható.
Több olyan kollégáról is tudok, akiknél nagyon szépen megfér egymás mellett a két világ ismerete, harmonikus használata. -
nyunyu
félisten
Egyébként meg lehet, hogy a tákolt eljárás ezredmásodpercekre kireszelése helyett inkább a folyamatot kéne átnyálazni, hogy az mennyire optimális, azzal valószínűleg SOKKAL többet nyernél.
Egy korábbi combos adatmigrációs projekten anyáztak velem állandóan a nagy adatmennyiségen lefutó sok adatellenőrző szkript "lassúsága" miatt.
(Én reszelgettem a szkripteket azon a projekten)Aztán következő projekten újrahasznosítottuk az egész adatellenőrző keretrendszert, csak annak a gazdája már nem volt a csapatunk része, így elmélyedhettem a kolléga kódjában, és tele volt kurzorokkal, meg dinamikusan összerakott SQL hívásokkal
Egészben az volt a legszebb, hogy az összes rekordra egyesével hívta meg az ellenőrző szkripteket.Azt meg tudni kell, hogy Oracle alatt egy exec 'select 1 from dual;' akkor is másfél másodpercig tart, ha fejreállsz közben...
Végeredmény az lett, hogy az egyesével futtatott szkripteket összefűztem egy clobba, aztán az lett dinamikusan futtatva.
Plusz kivettem a kurzort az egész elől, mert az ellenőrző szkriptek eleve úgy voltak megírva, hogy egész táblára futottak, így egy százezres táblán elég volt őket egyszer meghívni, nem kellett rekordonként külön-külön...Eredmény? 20 perc helyett lefutott az egész 15 másodperc alatt.
Tanulság?
Ne engedj Java/C/C# programozót SQLt "kódolni", mert az teljesen más műfaj.
(Pláne, ha natív SQL helyett Hibernate-tel vagy LinQ-el súlyosbítja)
Kiváncsi lettem volna, hogy a keretrendszer 2.0-át visszaportolva a légycsapó projektbe, mennyi ideig tartott volna a 3 betűs nagybank összes telefonvonalának adathelyesség ellenőrzése az eredeti 12 óra helyett
-
nyunyu
félisten
válasz
kw3v865 #5018 üzenetére
Akkor nézd meg most, mit csinál a query plan, aztán tegyél indexet a táblákra a join feltételek mentén, aztán ismét nézd meg mit csinál a query plan
Meg sokszor a statisztika gyűjtés is hasznos tud lenni nagyobb számítások előtt, hogy a DB optimalizálónak legalább valami halvány fogalma legyen arról, hogy melyik tábla mekkora, mert másképp célszerű csinálnia a joint kicsi tábláknál, mint nagyoknál.
-
nyunyu
félisten
válasz
kw3v865 #5016 üzenetére
Ja, hogy a sokmilliós táblán nincs index?
Úgy biztos lassú lesz.Ha meg dinamikus SQLt vagy egyéb hasonló külsőleg futtatandó varázslatokat hívsz, akkor meg pláne lemondhatsz az 1-2 másodperc alatti futásidőről.
Ha meg annyira időkritikus, akkor nincs mese, alá kell pakolni a vasat.
Esetleg elgondolkozni azon, hogy tetőfedéshez nem malteros kanalat kéne használni, mert azzal tényleg nem lehet haladni, akárhogy optimalizálod a processt. -
kw3v865
senior tag
válasz
martonx #5015 üzenetére
Akkor is kell az index a temp táblára, ha csak 15 rekordot tartalmaz? Ennél nem nagyon lehet benne több sor. Igazából nem látok most észrevehető javulást ezzel a temp táblás cache-eléssel. Nem erre számítottam, de ez van. Ennél a függvénynél minden egyes ms sokat számít. Ha már 1 ms-sel meg tudnám javítani a futásidejét, az is eredmény lenne. Valószínűleg a minimum 9 olyan select miatt nem lehet gyorsabb, amelyek táblát is használnak, azokon már nem tudok gyorsítani.
Explain analyse-szel sajnos nem tudom kideríteni mely része a lassú a függvénynek, tehát egyelőre csak tippelgetni tudok min lehetne még optimalizálni. Talán azt próbálom még meg, hogy ami nem feltétenül szükséges, azt kiteszem a C#-ba, és az eredményt paraméterként adom meg ennek a függvénynel. Bár ezek nem túl összettt műveletek.
-
nyunyu
félisten
-
kw3v865
senior tag
Sziasztok!
Ismét egy PostgreSQL-es kérdés, ezúttal már függvényt írok, PL/PgSQL nyelven: A függvényemben több select-et is futtatok, de előtte "be akarom cache"-elni egy lekérdezés eredményét, hogy később már sokkal gyorsabb legyen a többi select (leszűkíteni a sorok számát nagyon jelentősen).
Tehát kvázi ideiglenes táblát szeretnék létrehozni, amit csak az adott függvényen belül használok. CTE-vel sajnos nem megy, mert egy CTE-t csak egy select tud felhasználni, én pedig konkrétan 9 select-et fogok használni.
Próbáltam TEMPORARY TABLE-lel, de az lassúnak tűnik. A ROWTPYE vagy RECORD típus tökéletes lenne, de sajnos csak egy sort tud tárolni, így az nem jó. Tábla típus pedig sajnos nincs.
Van esetleg valami tippetek hogyan lehetne ezt a leghatákonyabban megcsinálni? Itt most nagyon fotnos lenne a jó teljesítmény, hiszen rendkívül időkritikus a dolog. -
kojakhu
újonc
válasz
bambano #5009 üzenetére
Közben meg is írta h mi a pontos elvárás, de a kódolástól nem láttam
Itt van, ami szerintem már helyes, csak azért h hátha meg lehet mégis csinálni.
Viszont performancia miatt nem lesz használható.
Max akkor, ha valahogy a sorok számát a rekurzív részben lehet limitálni. Pl ha lehet tudni, hogy max mekkora gapek vannak a logok között (ezt is ki lehet számolni akár), vagy esetleg az előző munkámmal lehet összeszerelni úgy h az ott előálló csoportokban kell csak részcsoportokat képezni.Szóval brahiból itt az újabb SQLFiddle link
Pls valaki mindenképpen válaszoljon (ha jó a megoldás, ha nem), mert a blogon "újoncként" nem írhatok csak 1-et amíg nincs rám válasz...Setup:
create table t (dt timestamp);
-- group 1
insert into t values (current_timestamp);
insert into t values (current_timestamp + interval '10' second);
insert into t values (current_timestamp + interval '59' second);
-- group 2
insert into t values (current_timestamp + interval '70' second);
insert into t values (current_timestamp + interval '71' second);
insert into t values (current_timestamp + interval '129' second);
-- group 3
insert into t values (current_timestamp + interval '200' second);
insert into t values (current_timestamp + interval '210' second);
insert into t values (current_timestamp + interval '220' second);
insert into t values (current_timestamp + interval '259' second);
-- group 4
insert into t values (current_timestamp + interval '260' second);
insert into t values (current_timestamp + interval '261' second);Lekérdezés:
WITH RECURSIVE rd(grp, mindt) AS (
SELECT 1 AS grp
, MIN(dt)
FROM t
UNION
SELECT rd.grp+1 AS grp
, FIRST_VALUE(t.dt) OVER (ORDER BY t.dt)
FROM t, rd
WHERE t.dt >= rd.mindt + INTERVAL '1' MINUTE
) -- rd
, grpd AS (
SELECT grp
, t.*
, MIN(dt) OVER (PARTITION BY grp) mindt
, MAX(dt) OVER (PARTITION BY grp) maxdt
, COUNT(*) OVER (PARTITION BY grp) cnt
FROM rd, t
WHERE t.dt >= rd.mindt AND t.dt < rd.mindt + INTERVAL '1' MINUTE
) -- grpd
SELECT v.*
, maxdt-mindt AS grp_duration
FROM grpd AS v
ORDER BY dt -
kojakhu
újonc
válasz
kw3v865 #4995 üzenetére
Hali, Lehet erre gondolsz. Addig egy entry egy csoport, amíg a timestamp gap nagyobb nem lesz mint 1 perc. Csoportokban meg lehet N db entry is amíg a gap nem túl nagy.
Ezt így lehet, pl.
Itt az SQLFiddle : [link]
Kód:
Setup:
create table t (dt timestamp);
-- group 1
insert into t values (current_timestamp - interval '10' second);
insert into t values (current_timestamp);
insert into t values (current_timestamp + interval '10' second);
-- group 2
insert into t values (current_timestamp + interval '120' second);
insert into t values (current_timestamp + interval '130' second);
-- group 3
insert into t values (current_timestamp + interval '220' second);
insert into t values (current_timestamp + interval '230' second);
Lekérdezés:
WITH
diffs AS (
SELECT dt
, LAG(dt) OVER (ORDER BY dt) AS prevdt
, LEAD(dt) OVER (ORDER BY dt) AS nextdt
, ROW_NUMBER() OVER (ORDER BY dt) AS rn
FROM t
) -- diffs
, group_gaps_and_flags AS (
SELECT v.*
, dt-prevdt AS prev_gap
, CASE WHEN prevdt IS NULL OR dt-prevdt > interval '1' minute
THEN 'Y'
END AS group_start_flag
, nextdt - dt AS next_gap
, CASE WHEN nextdt IS NULL OR nextdt-dt > interval '1' minute
THEN 'Y'
END AS group_end_flag
, CASE WHEN prevdt IS NULL OR dt-prevdt > interval '1' minute
THEN rn
END AS rn_if_start
FROM diffs AS v
) -- gaps_and_groups
, groups AS (
SELECT v.*
, MAX(rn_if_start) OVER (ORDER BY dt) -- ROWS BETWEEN UNBOUNDED_PRECEEDING AND CURRENT_ROW
AS my_group
FROM group_gaps_and_flags AS v
) -- groups
-- .
-- SELECT * FROM groups; -- separator for testing
-- .
SELECT my_group, MIN(dt), MAX(dt), COUNT(dt)
FROM groups
GROUP BY my_group
ORDER BY my_group
sorry, nem tudom még ezen a fórumon hogy kell kódot beszúrni jól... -
kw3v865
senior tag
Jól gondolod. Végigmenni a sorokon (timestamp növekvő sorrendben van), és csoportosítani őket egy új view-ba (aztán summázni, és egyéb aggregáló műveletek végezni rajtuk). Úgy szeretném, hogy az egyes csoportok első és utolsó időpontja között max. 1 perc legyen a különbség. Tehát ha valamelyik érték túllépi az 1 percet, akkor az már a következő csoportba kell, hogy tartozzon, és akkor ismét 0-ról indul az "óra".
-
Ispy
nagyúr
Vagy ha bármely elemhez vonatkoztatva kell lekérni, akkor meg cross join -nal kell csinálni egy Decrates-szórzatot úgy, hogy datum1 minusz datum2 és ahol a különbség -60 és +60 között van azokat kiszűrni, és akkor megkapjuk egy táblázatba, hogy mely dátumokhoz mely dátumok vannak az 1 perces intervallumba előre, hátra.
Csak ettől lehet meghajlik a vas....
-
Ispy
nagyúr
válasz
bambano #5003 üzenetére
El kell indulni a legkisebb dátumtól, ha jön az első dátum, ami 60 mp-en kívül van, akkor az egy csoport és indul újra a loop. Most azon lehet vitázni, hogy kisebb mint 60 vagy kisebb egyenlő. Ha megvan minden group, akkor meg kell határozni a group min és max értéke között az eltéréseket, azokat a groupokat meg ki kell szórni, ahol count(*)=1.
Már ha felfogtam mi a feladat...nem volt egyértelmű nekem az alap def.
-
bambano
titán
válasz
kw3v865 #4995 üzenetére
ezt nem lehet megoldani.
példa: legyen három timestampod, az első és a harmadik egymástól 1 perc 40 másodperc távolságra. A középső meg félúton. Akkor a középső melyikhez tartozik?egyébként timestampokat ki lehet vonni egymásból, timestamp lesz az eredmény, amit lehet konvertálni egész számmá.
Új hozzászólás Aktív témák
Hirdetés
- Proxmox VE
- Személyesen Zuckerberg toborozza a szuperintelligenciát építő AI-csapatot
- OFF TOPIC 44 - Te mondd, hogy offtopic, a te hangod mélyebb!
- TCL LCD és LED TV-k
- Geri Bátyó: B550 szűk keresztmetszet, de mi és miért?
- Elektromos cigaretta 🔞
- Ingatlanos topic!
- Apple MacBook
- Kuponkunyeráló
- Linux Mint
- További aktív témák...
- BESZÁMÍTÁS! MSI B450M R5 5500 32GB DDR4 512GB SSD RTX 3060 12GB Rampage SHIVA Chieftec 600W
- ÁRGARANCIA!Épített KomPhone i7 14700KF 32/64GB RAM RX 9070 16GB GAMER PC termékbeszámítással
- ÁRGARANCIA!Épített KomPhone Ryzen 7 9800X3D 32/64GB RAM RTX 5070Ti 16GB GAMER PC termékbeszámítással
- HATALMAS AKCIÓK! GARANCIA, SZÁMLA - Windows 10 11, Office 2016 2019 2021,2024, vírusírtók, VPN
- Telefon szerviz helyben - Gyors javítás, akár 30 perc alatt!
Állásajánlatok
Cég: PC Trade Systems Kft.
Város: Szeged
Cég: PC Trade Systems Kft.
Város: Szeged