Jump to content
php.lv forumi

Atlasīt pedeja id datus


reiniger

Recommended Posts

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 by reiniger
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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 by Mr.Key
Link to comment
Share on other sites

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

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...