reiniger Posted November 1, 2011 Report Share Posted November 1, 2011 (edited) Sveiki Mans kods SELECT d.* FROM weight AS d LEFT JOIN r_prop AS c ON (c.id = d.id_p) WHERE c.id_p = 28 ORDER by c.id DESC Man nepieciešams pēdējā c.id visus weight tabulas datus! Ja lietoju LIMIT 1, tad man atgriež tikai vienu ierakstu no weight tabulas. Un neredzu ko šeit varētu grupēt. Ceru ka sapratāt domu! Nevaru nekādīgi izdomāt risinājumu. Edited November 1, 2011 by reiniger Quote Link to comment Share on other sites More sharing options...
anonīms Posted November 1, 2011 Report Share Posted November 1, 2011 while? Quote Link to comment Share on other sites More sharing options...
briedis Posted November 1, 2011 Report Share Posted November 1, 2011 (edited) SELECT d.* FROM weight AS d LEFT JOIN r_prop AS c ON (c.id = d.id_p) WHERE c.id_p = 28 AND c.id = (SELECT MAX(id) FROM r_prop) ORDER by c.id DESC Nezinu, varbūt nostrādā :) Edited November 1, 2011 by briedis Quote Link to comment Share on other sites More sharing options...
reiniger Posted November 1, 2011 Author Report Share Posted November 1, 2011 Briedi tavs variants nostrādāja. Paldies Quote Link to comment Share on other sites More sharing options...
daGrevis Posted November 1, 2011 Report Share Posted November 1, 2011 'Varbūt nostrādā...' :D :D Quote Link to comment Share on other sites More sharing options...
CyHex Posted November 2, 2011 Report Share Posted November 2, 2011 Bet vai ātrāks nebūs variants ar diviem selektiem? Pirmajā iegūsti max(id) un otrajā iegūsti visus weight ierakstus ar šo id. Citādi tajā kombinētajā SQL pakārtotais select izpildīsies uz katru rindu, arī uz to, kas neatbilst kritērijiem, ne? Turklāt max() iet cauri visai r_prop tabulai un tā katru reizi pie katra no weight ieraksta. Drūmi nepārdomāti un izšķērdīgi man liekas. Nu jā, stilīgi jau ir visu smuki ar SQL atrisināt. Bet piedomāt pie ātrdarbības tomēr vajag. Nu, ja tev tur pāris ieraksti tabulās, tad var neuztraukties par ātrdarbību. Quote Link to comment Share on other sites More sharing options...
codez Posted November 2, 2011 Report Share Posted November 2, 2011 (edited) SELECT * FROM weight WHERE id_p=(SELECT id FROM r_prop ORDER BY id DESC LIMIT 1); Edited November 2, 2011 by codez Quote Link to comment Share on other sites More sharing options...
briedis Posted November 2, 2011 Report Share Posted November 2, 2011 SELECT * FROM weight WHERE id_p=(SELECT id FROM r_prop ORDER BY id DESC LIMIT 1); Izmēģināji šo? Man ir baigās aizdomas, ka kādreiz biju mēģinājis, bet man izspļāva, ka LIMIT nevar lietot apakšvaicājumos. Quote Link to comment Share on other sites More sharing options...
Kemito Posted November 2, 2011 Report Share Posted November 2, 2011 http://dev.mysql.com/doc/refman/5.0/en/subquery-errors.html Quote Link to comment Share on other sites More sharing options...
Mr.Key Posted November 2, 2011 Report Share Posted November 2, 2011 CyHex Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted November 2, 2011 Report Share Posted November 2, 2011 Bet vai ātrāks nebūs variants ar diviem selektiem? Pirmajā iegūsti max(id) un otrajā iegūsti visus weight ierakstus ar šo id. Vispārīgā gadījumā diez vai. Ja SQLs ir uzrakstīts normāli un gan bāze, gan cilvēks saprot ko un kā dara, tad parasti 1 SQLs strādā labāk nekā ntie, jo sevišķi, ja to dara ciklā. Citādi tajā kombinētajā SQL pakārtotais select izpildīsies uz katru rindu, arī uz to, kas neatbilst kritērijiem, ne? Nu to var pateikt tikai paskatoties izpildes plānu. Zīlēt kafijas biezumos nevajag. Šajā konkrētajā gadījumā, tā kā ir WHERE nosacījumi uz tabulu r_prop, kas it kā ir outer joinota, tad tam left join nav jēgas, patiesībā tas ir tas pats inner join. Līdz ar ko var mierīgi sākt SQL teikumu ķidāt no otra gala t.i. r_prop tabulas, ko MySQLs, kas tomēr ir pieteikami gudrs, arī dara. Kā par to pārliecināties? Tātad vajag izlasīt rakstu par MySQL explain extended :) OK skatamies piemēru izveidoju tabuliņas, ar 2 laukiem katru, id - primārā atslēga + indexus uz id_p kolonām, kas ir kā redzams ārējās atslēgas. un tagad ko mums rāda selekti: mysql> explain extended -> SELECT d.* FROM weight AS d -> LEFT JOIN r_prop AS c ON (c.id = d.id_p) -> WHERE c.id_p = 28 AND c.id = (SELECT MAX(id) FROM r_prop) -> ORDER by c.id DESC; +----+-------------+-------+-------+---------------+-------------+---------+-------+------+----------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+-------+---------------+-------------+---------+-------+------+----------+------------------------------+ | 1 | PRIMARY | c | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | | | 1 | PRIMARY | d | ref | weight_idx1 | weight_idx1 | 5 | const | 2 | 100.00 | Using where; Using index | | 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-------+-------+---------------+-------------+---------+-------+------+----------+------------------------------+ 3 rows in set, 1 warning (0.00 sec) mysql> show warnings -> ; +-------+------+---------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+---------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------+ | Note | 1003 | select `test`.`d`.`id` AS `id`,`test`.`d`.`id_p` AS `id_p` from `test`.`weight` `d` join `test`.`r_prop` `c` where ((`test` .`d`.`id_p` = (select max(`test`.`r_prop`.`id`) AS `MAX(id)` from `test`.`r_prop`))) order by '3' desc | +-------+------+---------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) 1kārt ka redzams, MySQL ir pārrakstījis selektu un taja nav vairs nekāda left join bet ir vienkārši join, tātad inner join. Te nu mēs redzam, ka oriģinālais selekts patiesība ir maldinošs un savukŗat MySQLs ir pietiekami gudrs lai to saprastu un veiktu vaicājuma transformāciju. 2kārt redzam, ka tabula c je r_prop tiek ņemta vispirms un tai tiek klāt joinota tabula weight. Tātad viss ir apgriezts otradi nekā pašā SQL teikumā rakstīts. 3kārt ja palasam googlē ko nozīmē "Select tables optimized away", tad tas nzoīmē to, ka šādu max vaicājumu MySQLs vispār izpilda optimizācijas fāzē un tālāk jau lieto kā konstanti. OK tagad lai redzētu ka left join tomēr mēdz palikt arī left join paskatamies, kas būtu, ja where klauzas nav. mysql> explain extended -> SELECT d.* FROM weight AS d -> LEFT JOIN r_prop AS c ON (c.id = d.id_p); +----+-------------+-------+--------+---------------+-------------+---------+-------------+------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+--------+---------------+-------------+---------+-------------+------+----------+-------------+ | 1 | SIMPLE | d | index | NULL | weight_idx1 | 5 | NULL | 7 | 100.00 | Using index | | 1 | SIMPLE | c | eq_ref | PRIMARY | PRIMARY | 4 | test.d.id_p | 1 | 100.00 | Using index | +----+-------------+-------+--------+---------------+-------------+---------+-------------+------+----------+-------------+ 2 rows in set, 1 warning (0.05 sec) mysql> show warnings; +-------+------+---------------------------------------------------------------------------------------------------------------------------- -----------------------------------------+ | Level | Code | Message | +-------+------+---------------------------------------------------------------------------------------------------------------------------- -----------------------------------------+ | Note | 1003 | select `test`.`d`.`id` AS `id`,`test`.`d`.`id_p` AS `id_p` from `test`.`weight` `d` left join `test`.`r_prop` `c` on((`test `.`c`.`id` = `test`.`d`.`id_p`)) where 1 | +-------+------+---------------------------------------------------------------------------------------------------------------------------- -----------------------------------------+ 1 row in set (0.00 sec) Tātad 1kārt - šai reizē arī versijā ko pilda MySQLs ir left join 2kārt - vispirms iet tabula d jeb weight un tikai tad c jeb r_prop Turklāt max() iet cauri visai r_prop tabulai un tā katru reizi pie katra no weight ieraksta. Jebkurā saprātīga bāzē ja lauks ir indeksēts, tad nekur fcauri neiet, bet paņem max vērtību no indexa. Drūmi nepārdomāti un izšķērdīgi man liekas. Tāpēc lai nebūtu man liekas, vajag pārliecināties kā tad tas notiek patiesībā. Nu jā, stilīgi jau ir visu smuki ar SQL atrisināt. Bet piedomāt pie ātrdarbības tomēr vajag. Nu, ja tev tur pāris ieraksti tabulās, tad var neuztraukties par ātrdarbību. Vairumā gadījumu tas ir gan stilīgi gan ātri, ja vien saprot ko raksta, kā raksta un kas jādara lai būtu ātri ;) Gints Plivna http://datubazes.wordpress.com Quote Link to comment Share on other sites More sharing options...
Mr.Key Posted November 3, 2011 Report Share Posted November 3, 2011 (edited) Gints, kā ir ar ACID tā subquery gadījumā, ja ir viens SQL? Sanāk, ka izpildes plāns paredz uz brīdi nolokot visu tabulu, no kuras izvāc ārā to Max ID? Tas, protams, attiecībā uz klasisku RDBMS (ne MyISAM dzinēju) Edited November 3, 2011 by Mr.Key Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted November 3, 2011 Report Share Posted November 3, 2011 Nu tas ir pilnībā atkarīgs no DBVS arhitektūras. Oraclē tas piemēram tiek realizēts tā, ka katram datu blokam ir atribūts SCN (system change number), kas ir monotoni augošs skaitlis. Katra vaicājuma sākumā tiek nofiksēts kāds ir šis SCNs (teiksim X), tad atlasot datus tiek skatīts kāds ir katra konkrētā datu bloka SCNs, ja tas ir mazāks nekā X, tad šis datu bloks der un dati tiek ņemti no tā. Ja datu bloks jau ir pārrakstīts (kāds cits process to izdarījis), tad iet uz speciālu atmiņas apgabalu, kas saucās UNDO un meklē tā paša bloka iepriekšējās versijas, līdz atrod tādu, kuram SCNs ir mazāks nekā X. Tādā veidā tiek nodrošināts konsistents skats uz dzīvi (t.i. uz to brīdi, kad palaiž vaicājumu), kā arī neviens lasītājs nebloķē rakstītājus un rakstītājs nebloķē lasītājus. Un tātad pēc katras pārrakstīšanas bloku iepriekšējās versijas tiek glabātas UNDO atmiņas apgabalā (vai tai atbilstošā tabultelpā uz diska). Protams, ka šis apgabals ir ierobežots un ar laiku vecās versijas tiek "izēstas" ārā, tādā gadījumā, ja vaicājums vairs nevar atrast pietiekami vecu datu bloka versiju (jo tas ir vilcies pietiekami ilgi un citi procesi ir daudz reizes to pārrakstījuši), tad vaicājums izlido ārā ar tipisku Oracles kļūdu snapshot too old rollback segment XX too small. Vairāk piemēram šeit http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:27330770500351 Bet šis mehānisms ir savādāks katrai DBVS, citām es tik smalki nepateikšu kā tas notiek, jālasa dokos. Piemēram SQL Serverī līdz pat 2005 versijai šķiet bija problemātiski vispār nodrošināt konsistentu lasīšanu, tur bija tiešam iespējamas visādas bloķēšanas vai arī dabūt visādus tādus brīnumus kā Non-repeatable Read u.c. zvēri - sk sīkāk http://sqlserverpedia.com/wiki/Transaction_Isolation_Levels 2005 versijā šis konsistentais mehānisms saucās snapshotizolation un arī tas izmanto speciālu logu (transaction logu), lai uzturētu ierakstu versijas. Gints Plivna http://datubazes.wordpress.com Quote Link to comment Share on other sites More sharing options...
spainis Posted November 4, 2011 Report Share Posted November 4, 2011 innoDB darbojas pēc MVCC tā kā problēmām nevajadzētu būt Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.