quote:Op donderdag 15 september 2011 12:04 schreef Catbert het volgende:
Ik vermoed dat 'ie een overzicht wil tonen van alle relaties met de omzet daarbij. Als hij geen index heeft op het veld wat die informatie bevat in de grote tabel zal 'ie voor iedere rij uit zo'n overzicht iedere keer die hele tabel door moeten ploegen.
Dan heb je niet de juiste indices geplaatst.quote:Op donderdag 15 september 2011 10:32 schreef wdn het volgende:
Maar zelfs met `indexering` op de tabel is het veel en veels te langzaam (30+ secondes) om alles bij elkaar te rapen.
Wat een snelle conclusie, een kenner?quote:Op donderdag 15 september 2011 12:30 schreef Tijn het volgende:
[..]
Dan heb je niet de juiste indices geplaatst.
Als er verder geen informatie wordt gegeven, kun je verder niet zoveel zeggen dan "je hebt het verkeerd gedaan"quote:Op donderdag 15 september 2011 12:43 schreef GlowMouse het volgende:
[..]
Wat een snelle conclusie, een kenner?
Ik heb net query gemaakt en gekeken met explain wat hij toevoegt, maar ik zie wat hij doet, maar niet waar hoeveel tijd inging zitten en hoeveel percentage de belasting van een onderdeel was. Zou wel tof zijn als hij zegt dat een bepaalde join 60% van de belasting vraagt en dat je daar kunt beginnen voor verbetering.quote:Op donderdag 15 september 2011 14:02 schreef Intrepidity het volgende:
Probeer eens een 'explain' voor je query te gooien om te kijken waar prestatiewinst te behalen valt.
http://dev.mysql.com/doc/refman/5.0/en/explain.html
MySQL geeft echt weinig informatiequote:Op donderdag 15 september 2011 14:45 schreef Catbert het volgende:
Je weet niks als hij niet post welke indices hij heeft.
De MSSQL query explain geeft overigens gewoon aan hoe zwaar een bepaald deel is.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | /* Drop stored procedure task_generate_sales_invoice first. */ if exists (select 1 from sysobjects where name = 'task_generate_sales_invoice' and type = 'P') drop procedure task_generate_sales_invoice go create procedure task_generate_sales_invoice ( @until_date date , @customer_id id ) as begin -- Do not count affected rows for performance SET NOCOUNT ON -- Generate sales invoice insert into sales_invoice select isnull((select max(sales_invoice_no) + 1 from sales_invoice), 1), customer_id, getdate(), dateadd(day, 30, getdate()), 0, 0, 0 from customer c where c.customer_id = @customer_id and exists (select 1 from hour h join project p on (p.project_id = h.project_id) where h.sales_invoice_id is null and p.customer_id = c.customer_id) -- Connect hours to sales invoice. update h set sales_invoice_id = (select max(sales_invoice_id) from sales_invoice i where i.customer_id = p.customer_id) from hour h join project p on (p.project_id = h.project_id) where h.sales_invoice_id is null and p.customer_id = @customer_id and h.date <= @until_date end go |
| 1 2 | Msg 213, Level 16, State 1, Procedure task_generate_sales_invoice, Line 16 Insert Error: Column name or number of supplied values does not match table definition. |
Kolomnaam volgens mij.quote:Op vrijdag 16 september 2011 16:05 schreef ViPeRII het volgende:
Een van je tabelnamen die geselecteerd worden, bestaat niet
Onzin. Echt.quote:Op donderdag 15 september 2011 12:30 schreef Tijn het volgende:
[..]
Dan heb je niet de juiste indices geplaatst.
Nee, de index staat op de relatie natuurlijk (als ik die niet zet gaat mysql onderuitquote:Op donderdag 15 september 2011 12:04 schreef Catbert het volgende:
Ik vermoed dat 'ie een overzicht wil tonen van alle relaties met de omzet daarbij. Als hij geen index heeft op het veld wat die informatie bevat in de grote tabel zal 'ie voor zo'n overzicht iedere keer die hele tabel door moeten ploegen.
Idee om je factuur historie tabel te gaan sharden? Dat zou de boel een stuk moeten versnellen.quote:Op vrijdag 16 september 2011 17:13 schreef wdn het volgende:
[..]
Onzin. Echt.
[..]
Nee, de index staat op de relatie natuurlijk (als ik die niet zet gaat mysql onderuit).
Het is puur de hoeveelheid data (op dit moment 12.3 miljoen records) en hoeveelheid geheugen die ik kan gebruiken.
Maar uit de discussie hier kan ik al bepalen dat mijn vraag met 'nee' beantwoord moet worden: stored procedures is niet de oplossing.
relaties kent een 1500 records.
factuur historie 12.3m records.
factuur historie wordt op bedrijf, debiteur, contract factuur, regel doorlopen (en dat is de volledige primary key met debiteur ertussen). Geforceerd met een USE INDEX.
Ik had het idee om een soort van afgeleide tabel boven op deze tabel te leggen (met een PK bedrijf, debiteur, jaar, omzet).
| 1 2 3 4 5 | if($pages >= 1 && $page <= $pages){ for ($x=1; $x<=$pages; $x++) { echo ($x == $page) ? "<strong><a href='/nieuws/overzicht&page=".$x."'>".$x."</a></strong> " : "<a href='/nieuws/overzicht&page=".$x."'>".$x."</a> "; } } |
Dat is erg inefficiënt, je kunt beter in die for-loop $x in 1x flink ophogen als je bij de puntjes aanbelandt.quote:Op zondag 18 september 2011 18:53 schreef Tijn het volgende:
Gewoon een ifje in je for-loop die kijkt of $x kleiner is dan 3 en een ifje die kijkt of $x groter is dan $pages - 3 toch?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | if($pages >= 1 && $page <= $pages){ if($page >= 2){ $nextpage = $page+1; $previouspage = $page-1; if($page == $pages){ echo "<a href='overzicht&page=1'>Eerste</a> | <a href='overzicht&page=$previouspage'>Vorige</a> <strong>...<a href='overzicht&page=$page'>$page</a></strong>"; } else{ echo "<a href='overzicht&page=1'>Eerste</a> | <a href='overzicht&page=$previouspage'>Vorige</a> <strong>...<a href='overzicht&page=$page'>$page</a>...</strong> <a href='overzicht&page=".$nextpage."'>Volgende</a> | <a href='overzicht&page=$pages'>Laatste</a>"; } } else{ $nextpage = $page+1; echo "<strong><a href='overzicht&page=$page'> $page</a>...</strong> <a href='overzicht&page=".$nextpage."'>Volgende</a> | <a href='overzicht&page=$pages'>Laatste</a>"; } } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | <?php /** * * Format base_url: 'pages.php?id=1&start=%d' * The %d string is for the count element * * Decoration array parameters * - param: Boolean $add_prevnext_text * - param: String $selected_format * - param: String $base_url_html * - param: String $spacer * - param: String $breaker * * @param String $base_url * @param Integer $num_items * @param Integer $per_page * @param Integer $start_item * @param Array $add_prevnext_text * @return String */ function GeneratePagination($base_url, $num_items, $per_page, $start_item, $decoration = array()) { $add_prevnext_text = false; $selected_format = '<b>%d</b>'; $base_url_html = sprintf('<a href="%s">%s</a>', $base_url, '%s'); $spacer = ' '; $breaker = ' ... '; $previous_text = 'Previous'; $next_text = 'Next'; if ( $num_items == 0 ) { throw new Exception('mag geen 0 zijn want die kun je niet delen door een getal.'); } if ( isset($decoration['add_prevnext_text']) === true ) { $add_prevnext_text = true; } if ( isset($decoration['previous_text']) === true ) { $previous_text = $decoration['previous_text']; } if ( isset($decoration['next_text']) === true ) { $next_text = $decoration['next_text']; } if ( isset($decoration['selected_format']) === true ) { $selected_format = $decoration['selected_format']; } if ( isset($decoration['base_url_html']) === true ) { $base_url_html = sprintf($decoration['base_url_html'], $base_url, '%s'); } if ( isset($decoration['spacer']) === true ) { $spacer = $decoration['spacer']; } if ( isset($decoration['breaker']) === true ) { $breaker = $decoration['breaker']; } $total_pages = ceil($num_items/$per_page); if ( $total_pages == 1 ) { return ''; } $on_page = floor($start_item / $per_page) + 1; $page_string = ''; if ( $total_pages > 10 ) { $init_page_max = ( $total_pages > 3 ) ? 3 : $total_pages; for($i = 1; $i < $init_page_max + 1; $i++) { $page_string .= ( $i == $on_page ) ? sprintf($selected_format, $i) : sprintf($base_url_html, ( ( $i - 1 ) * $per_page ), $i); if ( $i < $init_page_max ) { $page_string .= $spacer; } } if ( $total_pages > 3 ) { if ( $on_page > 1 && $on_page < $total_pages ) { $page_string .= ( $on_page > 5 ) ? $breaker : $spacer; $init_page_min = ( $on_page > 4 ) ? $on_page : 5; $init_page_max = ( $on_page < $total_pages - 4 ) ? $on_page : $total_pages - 4; for($i = $init_page_min - 1; $i < $init_page_max + 2; $i++) { $page_string .= ($i == $on_page) ? sprintf($selected_format, $i) : sprintf($base_url_html, ( ( $i - 1 ) * $per_page ), $i); if ( $i < $init_page_max + 1 ) { $page_string .= $spacer; } } $page_string .= ( $on_page < $total_pages - 4 ) ? $breaker : $spacer; } else { $page_string .= $breaker; } for($i = $total_pages - 2; $i < $total_pages + 1; $i++) { $page_string .= ( $i == $on_page ) ? sprintf($selected_format, $i) : sprintf($base_url_html, ( ( $i - 1 ) * $per_page ), $i); if( $i < $total_pages ) { $page_string .= $spacer; } } } } else { for( (int) $i = 1; $i < $total_pages + 1; $i++ ) { $page_string .= ( $i == $on_page ) ? sprintf($selected_format, $i) : sprintf($base_url_html, ( $i - 1 ) * $per_page, $i); if ( $i < $total_pages ) { $page_string .= $spacer; } } } if ( $add_prevnext_text ) { if ( $on_page > 1 ) { $page_string = sprintf($base_url_html, ( $on_page - 2 ) * $per_page, $previous_text) . ' ' . $page_string; } if ( $on_page < $total_pages ) { $page_string .= (string) ' ' . sprintf($base_url_html, $on_page * $per_page, $next_text); } } return $page_string; } ?> |
Ik vindquote:Op zondag 18 september 2011 22:30 schreef ralfie het volgende:
isset($decoration['breaker']) === true
isset poept toch alleen maar true of false? waarom die === true ?
| 1 2 3 | <?php if( functie($parameter) === true ) { } ?> |
| 1 2 3 | <?php if( functie($parameter)) { } ?> |
Bij isset() is dat nutteloos want die returned sowieso alleen true of false.quote:Op maandag 19 september 2011 07:47 schreef Pakspul het volgende:
En de === i.p.v. de == die gebruikelijk is in een statement: http://www.php.net/manual/en/language.operators.comparison.php. Die controleert ook of het type hetzelfde is.
En dan komt reden 1 om de hoek kijkenquote:Op maandag 19 september 2011 08:17 schreef mstx het volgende:
[..]
Bij isset() is dat nutteloos want die returned sowieso alleen true of false.
Bedanktquote:Op dinsdag 20 september 2011 11:19 schreef GlowMouse het volgende:
SELECT producten.naam, COUNT(*)
FROM verkocht
LEFT JOIN producten ON verkocht.pro_id=producten.pro_id
GROUP BY producten.pro_id
Geen COUNT(*) maar COUNT(id) doen. Bij * pakt hij de index niet meequote:Op dinsdag 20 september 2011 11:19 schreef GlowMouse het volgende:
SELECT producten.naam, COUNT(*)
FROM verkocht
LEFT JOIN producten ON verkocht.pro_id=producten.pro_id
GROUP BY producten.pro_id
Oja het moet inderdaad een count zijn, foutje.quote:Op dinsdag 20 september 2011 11:19 schreef GlowMouse het volgende:
SELECT producten.naam, COUNT(*)
FROM verkocht
LEFT JOIN producten ON verkocht.pro_id=producten.pro_id
GROUP BY producten.pro_id
COUNT(*) is exact hetzelfde als COUNT(kolom die NOT NULL is)quote:Op dinsdag 20 september 2011 11:22 schreef Intrepidity het volgende:
[..]
Geen COUNT(*) maar COUNT(id) doen. Bij * pakt hij de index niet mee
En de GROUP BY is ook op een andere tabel, anders krijg je producten met 0 bestellingen niet te zien.quote:Op dinsdag 20 september 2011 11:22 schreef mstx het volgende:
[..]
Oja het moet inderdaad een count zijn, foutje.
Klopt, maar toch pakt hij een eventuele index niet mee tenzij je expliciet een kolom met index specificeert. MySQL is een hacky stuk code. Zolang je gewoon de PK in een COUNT gebruikt is er niets aan het handjequote:Op dinsdag 20 september 2011 11:34 schreef GlowMouse het volgende:
[..]
COUNT(*) is exact hetzelfde als COUNT(kolom die NOT NULL is)
Ik heb hier aardig wat mee getest en dit heb ik nog nooit gezien. Heb je een dataset, een query, en een MySQL-versienummer waarbij dit optreedt?quote:Op dinsdag 20 september 2011 11:36 schreef Intrepidity het volgende:
[..]
Klopt, maar toch pakt hij een eventuele index niet mee tenzij je expliciet een kolom met index specificeert. MySQL is een hacky stuk code. Zolang je gewoon de PK in een COUNT gebruikt is er niets aan het handje
| 1 2 3 4 5 6 7 8 | CREATE TABLE `comments` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `content_id` timestamp NULL DEFAULT NULL, -- timestamp ja :D *snip* hoop blabla *snip* `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `by_content_id` (`content_id`,`created_at`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
| 1 2 3 4 5 6 7 8 9 10 11 | SELECT COUNT(*) FROM ( SELECT 1 FROM comments GROUP BY content_id HAVING MAX(created_at) > ( SELECT MAX(created_at) FROM comments WHERE content_id = FROM_UNIXTIME(1316465786) ) ) AS predecessors |
Ik heb nu geen tijd (@ werk), maar zal vanavond eens wat gaan testenquote:Op dinsdag 20 september 2011 11:56 schreef GlowMouse het volgende:
[..]
Ik heb hier aardig wat mee getest en dit heb ik nog nooit gezien. Heb je een dataset, een query, en een MySQL-versienummer waarbij dit optreedt?
quote:Op dinsdag 20 september 2011 11:57 schreef Thomass het volgende:
GlowMouse, hoe ben jij ooit zon MySQL-baas geworden als ik mag vragen?
| 1 2 3 4 5 6 7 | SELECT COUNT(DISTINCT content_id) FROM comments WHERE created_at > ( SELECT MAX(created_at) FROM comments WHERE content_id = FROM_UNIXTIME(1316465786) ) |
| 1 2 3 4 | SELECT COUNT(DISTINCT c1.content_id) FROM comments c1 LEFT JOIN c2 ON(c1.content_id=c2.content_id AND c2.created_at>[subquery eerst uitvoeren en het resultaat hier zetten]) WHERE c2.content_id IS NULL |
Deel 3 komt eraan: http://www.xaprb.com/blog(...)mysql-third-edition/quote:Op dinsdag 20 september 2011 12:04 schreef GlowMouse het volgende:
[..]
http://shop.oreilly.com/product/9780596101718.do en http://www.mysqlperformanceblog.com/ helemaal lezen, en veel uitproberen. De meeste kennis heb ik in een maandje of 2-3 wel verworven.
Binnen je applicatie heb je er niet zo veel aan afaik. Je gebruikt het direct op MySQL om je queries te optimaliseren voordat je ze in je applicatie gaat gebruiken.quote:Op dinsdag 20 september 2011 12:51 schreef Sitethief het volgende:
Is EXPLAIN ook goed in te zetten als je een PDO class hebt opgebouwd waarmee je al je queries afhandelt?
Het is verwarrend ja maar ik bedoelde wel een groter dan. Item met meest recent comment heeft 0 predecessors, t item met het op-ena-meest recente comment heeft 1 predecessor enz.quote:Op dinsdag 20 september 2011 12:14 schreef GlowMouse het volgende:
Volgens mij bedoel je op regel 6 een < ipv een >. Voor een < kun je zoiets doen:
[ code verwijderd ]
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | mysql> show create table comments2\G *************************** 1. row *************************** Table: comments2 Create Table: CREATE TABLE `comments2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `content_id` int(10) unsigned DEFAULT NULL, `created_at` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `by_content_id` (`content_id`,`created_at`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> select count(*) from comments2; +----------+ | count(*) | +----------+ | 2359296 | +----------+ 1 row in set (0.02 sec) mysql> select content_id, max(created_at) from comments2 group by content_id order by max(created_at) asc; +------------+-----------------+ | content_id | max(created_at) | +------------+-----------------+ | 1 | 3 | | 2 | 6 | *snip* | 2654208 | 5308416 | | 3981312 | 7962624 | +------------+-----------------+ 95 rows in set (0.04 sec) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | mysql> SELECT COUNT(DISTINCT content_id) -> FROM comments2 -> WHERE created_at > ( -> SELECT MAX(created_at) -> FROM comments2 -> WHERE content_id = 2654208 -> ); +----------------------------+ | COUNT(DISTINCT content_id) | +----------------------------+ | 1 | +----------------------------+ 1 row in set (1.58 sec) mysql> SELECT COUNT(*) -> FROM ( -> SELECT 1 -> FROM comments2 -> GROUP BY content_id -> HAVING MAX(created_at) > ( -> SELECT MAX(created_at) -> FROM comments2 -> WHERE content_id = 2654208 -> ) -> ) AS predecessors; +----------+ | COUNT(*) | +----------+ | 1 | +----------+ 1 row in set (0.01 sec) |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | mysql> explain SELECT COUNT(*) -> FROM ( -> SELECT 1 -> FROM comments2 -> GROUP BY content_id -> HAVING MAX(created_at) > ( -> SELECT MAX(created_at) -> FROM comments2 -> WHERE content_id = 2654208 -> ) -> ) AS predecessors; +----+-------------+-----------+-------+---------------+---------------+---------+------+------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+---------------+---------+------+------+------------------------------+ | 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | | 2 | DERIVED | comments2 | range | NULL | by_content_id | 5 | NULL | 95 | Using index for group-by | | 3 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-----------+-------+---------------+---------------+---------+------+------+------------------------------+ 3 rows in set (0.01 sec) mysql> explain SELECT COUNT(DISTINCT content_id) -> FROM comments2 -> WHERE created_at > ( -> SELECT MAX(created_at) -> FROM comments2 -> WHERE content_id = 2654208 -> ); +----+-------------+-----------+-------+---------------+---------------+---------+------+---------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+---------------+---------+------+---------+------------------------------+ | 1 | PRIMARY | comments2 | index | NULL | by_content_id | 9 | NULL | 2359296 | Using where; Using index | | 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-----------+-------+---------------+---------------+---------+------+---------+------------------------------+ 2 rows in set (0.00 sec) |
quote:Op dinsdag 20 september 2011 12:51 schreef Sitethief het volgende:
Is EXPLAIN ook goed in te zetten als je een PDO class hebt opgebouwd waarmee je al je queries afhandelt?
Dat hangt er maar net vanaf. Wij werken hier bv aan een behoorlijk grote (web)applicatie met enkele duizenden query's waarvan ook een flink deel automatisch gegenereerd is. We hebben pagina's met meer dan 100 query's en dan is het nogal fijn als je niet alles met de hand hoeft na te lopen. We hebben daarom op de devservers gewoon een analyser meelopen die voor iedere query ook een explain uitvoert en deze analyseert. Als het systeem denkt dat het beter kan zet hij netjes een warnings icoontje bij onze query log die onder iedere pagina staat met de values, tijd etc. Klik je er op krijg je de explain, backtraces en nog veel meer debug informatiequote:Op dinsdag 20 september 2011 13:00 schreef Intrepidity het volgende:
[..]
Binnen je applicatie heb je er niet zo veel aan afaik. Je gebruikt het direct op MySQL om je queries te optimaliseren voordat je ze in je applicatie gaat gebruiken.
Hmm een automatische tool die een samenvatting op iedere pagina zet vs een losse tool die je handmatig moet draaien, eerst een netwerk dump maken en dan analyseren. Ik weet het welquote:Op woensdag 21 september 2011 17:40 schreef GlowMouse het volgende:
Dit werkt veel lekkerder:
http://www.mysqlperforman(...)maatkit-and-tcpdump/
Je klinkt imo als een random persoon die gewoon de laatste hype na blaat.quote:
| 1 | SELECT * FROM `producten` WHERE `prijs` = 15 OR `prijs` = 25; |
Dat ben ik altijd wel gelukkigquote:Op woensdag 21 september 2011 21:29 schreef Diabox het volgende:
Maakt niet uit, zolang je maar consistent blijft in gebruik ervan (wel zo netjes).
number_format();quote:Op woensdag 21 september 2011 23:45 schreef Dalando het volgende:
Ik heb een getal. 1940239315. En ik moet het leesbaar maken via PHP, dus 1.940.239.315 ofzo. Hoe?
| Forum Opties | |
|---|---|
| Forumhop: | |
| Hop naar: | |