Zware query van +36.000 rows printen
Ik heb een script waarbij ik via jQuery een tabel aanmaak waarin ik heel snel een row kan opzoeken tussen 36.000+ andere rows.
Maar het duurt HEEEEL lang voordat het geladen is.
Weet iemand hoe ik dit kan verbeteren?
De query:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$sql = "
SELECT
ID,
client_id,
name,
contact
FROM
clients
ORDER BY
name, ID
";
?>
$sql = "
SELECT
ID,
client_id,
name,
contact
FROM
clients
ORDER BY
name, ID
";
?>
De tabel:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
CREATE TABLE IF NOT EXISTS `clients` (
`ID` int(20) NOT NULL,
`client_id` int(20) NOT NULL,
`name` varchar(255) NOT NULL,
`street` varchar(255) NOT NULL,
`postal` varchar(255) NOT NULL,
`city` varchar(255) NOT NULL,
`country` varchar(255) NOT NULL,
`phone` varchar(255) NOT NULL,
`since` varchar(255) NOT NULL,
`changed` varchar(255) NOT NULL,
`contact` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=36085 DEFAULT CHARSET=latin1;
?>
CREATE TABLE IF NOT EXISTS `clients` (
`ID` int(20) NOT NULL,
`client_id` int(20) NOT NULL,
`name` varchar(255) NOT NULL,
`street` varchar(255) NOT NULL,
`postal` varchar(255) NOT NULL,
`city` varchar(255) NOT NULL,
`country` varchar(255) NOT NULL,
`phone` varchar(255) NOT NULL,
`since` varchar(255) NOT NULL,
`changed` varchar(255) NOT NULL,
`contact` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=36085 DEFAULT CHARSET=latin1;
?>
Alvast bedankt!
Verder zou je een index op name kunnen aanmaken zodat het sorteren sneller gaat.
client_id en name zijn indexes
Heb je vastgesteld dat de laadtijd echt zit in het uitvoeren van de query, of toch ergens anders? Als je heel veel data naar je scherm stuurt, dan kan dat op zichzelf ook al veel tijd kosten.
Wanneer je één row wilt selecteren voeg dan een WHERE clausule toe.
Datatables.
Code (php)
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
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
<table id="table_archive" class="table table-striped table-bordered table-responsive" cellspacing="0" width="100%">
<thead>
<tr>
<th>Client ID</th>
<th>Bedrijfsnaam</th>
<th>Contact persoon</th>
<th>Actie</th>
</tr>
</thead>
<tbody>
<?php
$sql = "
SELECT
ID,
client_id,
name,
contact
FROM
clients
";
if(!$res = mysqli_query($mysqli, $sql))
{
trigger_error('Fout in query: '.mysqli_error());
}
else
{
while($row = mysqli_fetch_assoc($res))
{
echo '<tr>';
echo '<td>'.$row['client_id'].'</td>';
echo '<td>'.ucfirst(strtolower($row['name'])).'</td>';
echo '<td>'.ucfirst(strtolower($row['contact'])).'</td>';
echo '<td class="center">';
echo '<a class="btn btn-info btn-xs" href="'.SITE_URL.'admin/gebruikers_wijzigen.php?id='.$row['ID'].'" title="Wijzigen">
<span class="glyphicon glyphicon-edit" style="margin-right:0;"></span>
</a> ';
if(empty($disabled[$row['ID']]))
{
echo '<a onclick="show_confirm('.$row['ID'].')" class="btn btn-danger btn-xs" title="Blokkeren">
<span class="glyphicon glyphicon-remove" style="margin-right:0;"></span>
</a>';
}
else
{
echo '<a onclick="de_show_confirm('.$disabled[$row['ID']].')" class="btn btn-success btn-xs" title="Deblokkeren">
<span class="glyphicon glyphicon-ok-sign" style="margin-right:0;"></span>
</a>';
}
echo '</td>';
echo '</tr>';
}
}
?>
</tbody>
</table>
<thead>
<tr>
<th>Client ID</th>
<th>Bedrijfsnaam</th>
<th>Contact persoon</th>
<th>Actie</th>
</tr>
</thead>
<tbody>
<?php
$sql = "
SELECT
ID,
client_id,
name,
contact
FROM
clients
";
if(!$res = mysqli_query($mysqli, $sql))
{
trigger_error('Fout in query: '.mysqli_error());
}
else
{
while($row = mysqli_fetch_assoc($res))
{
echo '<tr>';
echo '<td>'.$row['client_id'].'</td>';
echo '<td>'.ucfirst(strtolower($row['name'])).'</td>';
echo '<td>'.ucfirst(strtolower($row['contact'])).'</td>';
echo '<td class="center">';
echo '<a class="btn btn-info btn-xs" href="'.SITE_URL.'admin/gebruikers_wijzigen.php?id='.$row['ID'].'" title="Wijzigen">
<span class="glyphicon glyphicon-edit" style="margin-right:0;"></span>
</a> ';
if(empty($disabled[$row['ID']]))
{
echo '<a onclick="show_confirm('.$row['ID'].')" class="btn btn-danger btn-xs" title="Blokkeren">
<span class="glyphicon glyphicon-remove" style="margin-right:0;"></span>
</a>';
}
else
{
echo '<a onclick="de_show_confirm('.$disabled[$row['ID']].')" class="btn btn-success btn-xs" title="Deblokkeren">
<span class="glyphicon glyphicon-ok-sign" style="margin-right:0;"></span>
</a>';
}
echo '</td>';
echo '</tr>';
}
}
?>
</tbody>
</table>
- Aar -:
Gelieve in het vervolg bij code de [code][/code]-tags gebruiken.
Hier kan je meer lezen over de mogelijke opmaakcodes.
Alvast bedankt!
Hier kan je meer lezen over de mogelijke opmaakcodes.
Alvast bedankt!
Gewijzigd op 12/06/2015 13:21:37 door - Ariën -
Probeer, zeker bij zoveel rijen zo min mogelijk HTML te tonen. Des te sneller is je overdracht.
Alle onclick() kunnen er uit. Vang dat af met 1 regel jQuery.
De class= kan er ook uit. Doe dit via table tr td.center a
Haal de title="" weg. Die is leuk, maar wordt in je applicatie toch niet gebruikt (sorry, html-validators)
Verwijder de inline CSS op je <span>
Je gebruikt glyphicon: is die niet traag? Verwijder class="glyphicon ...." eens. Gaat het dan sneller?
Je PHP kan niet veel sneller/beter.
Je SQL wellicht wel door INDEXES, al gebruik je die bij een SELECT * niet echt.
Toevoeging op 10/06/2015 19:03:04:
En als je echt snel wil zoeken: kijk eens naar AJAX en laat de database in de database zoeken ;)
Honestly, hang er een limiet in en/of maak een slimmere in- of opdeling.
Bijvoorbeeld: op bedrijf(snaam) of beginletter van achternaam. Of maak er een zoekpaneeltje bij dat je zelf kunt sorteren en filteren.
Met 36.000 records tegelijkertijd uitspugen creëer je niet meer, maar minder overzicht. Dat is terug naar het spreadsheet tijdperk.
Eddy E op 10/06/2015 19:02:21:
Je PHP kan niet veel sneller/beter.
Je SQL wellicht wel door INDEXES, al gebruik je die bij een SELECT * niet echt.
Je SQL wellicht wel door INDEXES, al gebruik je die bij een SELECT * niet echt.
Je zou om de 100 rijen een ob_flush() of flush() kunnen zetten, zodat de client alvast beeld heeft. Dan is de applicatie nog steeds even traag (strikt genomen zelfs wat trager), maar valt het minder op.
Verder zou je de SELECT-query kunnen uitbreiden met een ORDER BY voor de meest gebruikte sorteervolgorde. De meeste gebruikers sorteren een tabel zó dat ze de belangrijkste rijen bovenaan zien. En dáárop zet je vervolgens ook een INDEX met ASC of DESC.
Aangezien je INT(20) gebruikt in de tabeldefinitie en een PRIMARY KEY ontbreekt, vermoed ik zo dat we niet de hele tabel zien of de tabel inderdaad niet goed is ingedeeld.
Gewoon jSON uitpoepen :)
http://www.fleischer.nl/Grundfos/handlers/clients_processing.php
Nu gaat ie lekkah!
Bedankt !
Quote:
Oeps...
Hier is even iets mis gegaan.
Hier is even iets mis gegaan.
Joni Fleischer op 10/06/2015 19:59:04:
Ik heb het al!!!
Gewoon jSON uitpoepen :)
http://www.fleischer.nl/Grundfos/handlers/clients_processing.php
Nu gaat ie lekkah!
Bedankt !
Gewoon jSON uitpoepen :)
http://www.fleischer.nl/Grundfos/handlers/clients_processing.php
Nu gaat ie lekkah!
Bedankt !
Omdat niemand anders het vermeld, doe ik het maar even om het punt maar even duidelijk te maken.
NIEMAND heeft 36k rows nodig om wat te gaan doen. 1k resultaten is meer dan voldoende voor elk type website. En met 1k resultaten ben je zelfs gewoon slecht bezig.
Als jij denkt dat JSON jouw uitkomst is, prima en dan raad ik jouw aan om ergens hier te gaan eten.
Ik zeg er wel bij dat de database vrijwel altijd erg efficiënt is met het ophalen van data. Het verwerken daarvan zal jouw bottleneck wezen.
Niemand commentaar op veldoptimalisatie? Telefoonnummers, postcodes hebben een redelijk standaard opmaak en lengte, een stuk korter dan 255 tekens. Hier kan je ook een boel winst op behalen.
- wes - op 11/06/2015 09:26:53:
Telefoonnummers, postcodes hebben een redelijk standaard opmaak en lengte, een stuk korter dan 255 tekens. Hier kan je ook een boel winst op behalen.
Bij een VARCHAR helaas niet. Als je altijd postcodes van maximaal 7 karakters opslaat, maakt het voor de performance niet uit of je daarvoor nu een VARCHAR(7) of VARCHAR(255) gebruikt. Die extra ruimte wordt gewoon niet gebruikt als daarvoor geen data is.
Wat wel helpt: als postcodes altijd precies 7 karakters zijn, kun je beter een CHAR(7) gebruiken.
Verder kan bijvoorbeeld de `country` varchar(255) naar een aparte tabel. Dan heb je voor de sleutels alleen nog een TINYINT nodig.
since en changed klinkt als datum. In dat geval lijkt me varchar niet wenselijk.
Wat is de use case voor de oplossing van Joni?
Dat moet overgestuurd worden en vervolgens moet de browser dat omzetten in iets dat getoond moet worden.
Met een beetje pech is je browser ook nog eens een paar duizend keer bezig om de breedte van elke kolom steeds opnieuw te bepalen.
Mogelijk dat daarna jQuery snel kan zoeken, maar je laadtijd is enorm.
Daarnaast: ook jQuery krijgt direct een dataset van 36000 records te verhapstukken. Dat moet ook ergens in het javascript geheugen komen.
Ik zou het meer zoeken in een soort auto-suggest oplossing waarbij je tijdens het typen in de database gaat zoeken met ajax
Joni Fleischer op 10/06/2015 18:04:25:
Hij moet juist die 36.000 rijen invoegen vanwege dat jQuery er een tabel van maakt waar je in kan zoeken.
Datatables.
Datatables.
Dus ik begrijp het goed als ik er vanuit ga dat je Datatables gebruikt? Dan zou ik gebruik maken van laden via Ajax, in combinatie met de optie pageLength.
Als het script dat de data ophaalt dan goed is haal je een maximaal aantal rijen op, die aan de filters voldoet van DataTables. Zie daarvoor Server side processing.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<table id="table_archive" class="display table table-striped table-bordered table-responsive" cellspacing="0" width="98%" data-page-length='18'>
<thead>
<tr>
<th width="10%">Client ID</th>
<th>Bedrijfsnaam</th>
<th width="20%">Contact persoon</th>
<th width="30%">E-mailadres</th>
<th width="5%">Actie</th>
</tr>
</thead>
</table>
<thead>
<tr>
<th width="10%">Client ID</th>
<th>Bedrijfsnaam</th>
<th width="20%">Contact persoon</th>
<th width="30%">E-mailadres</th>
<th width="5%">Actie</th>
</tr>
</thead>
</table>
Dan de jQuery code:
Code (php)
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
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
var table = $('#table_archive').DataTable( {
"language": {
"sProcessing": "Bezig...",
"sLengthMenu": "_MENU_ resultaten weergeven",
"sZeroRecords": "Geen resultaten gevonden",
"sInfo": "_START_ tot _END_ van _TOTAL_ resultaten",
"sInfoEmpty": "Geen resultaten om weer te geven",
"sInfoFiltered": " (gefilterd uit _MAX_ resultaten)",
"sInfoPostFix": "",
"sSearch": "Zoeken:",
"sEmptyTable": "Geen resultaten aanwezig in de tabel",
"sInfoThousands": ".",
"sLoadingRecords": "Een moment geduld aub - bezig met laden...",
"oPaginate": {
"sFirst": "Eerste",
"sLast": "Laatste",
"sNext": "Volgende",
"sPrevious": "Vorige"
}
},
"processing": true,
"serverSide": true,
"ajax": "handle/clients_processing.php",
"columnDefs": [ {
"targets": -1,
"data": null,
"defaultContent": "<a class='btn btn-info btn-xs' href='#' title='Wijzigen'><span class='glyphicon glyphicon-edit' style='margin-right:0;'></span></a>"
} ]
} );
$('#table_archive tbody').on( 'click', 'a', function () {
var data = table.row( $(this).parents('tr') ).data();
$(this).attr("href", "edit.php?id="+ data[ 4 ]);
});
"language": {
"sProcessing": "Bezig...",
"sLengthMenu": "_MENU_ resultaten weergeven",
"sZeroRecords": "Geen resultaten gevonden",
"sInfo": "_START_ tot _END_ van _TOTAL_ resultaten",
"sInfoEmpty": "Geen resultaten om weer te geven",
"sInfoFiltered": " (gefilterd uit _MAX_ resultaten)",
"sInfoPostFix": "",
"sSearch": "Zoeken:",
"sEmptyTable": "Geen resultaten aanwezig in de tabel",
"sInfoThousands": ".",
"sLoadingRecords": "Een moment geduld aub - bezig met laden...",
"oPaginate": {
"sFirst": "Eerste",
"sLast": "Laatste",
"sNext": "Volgende",
"sPrevious": "Vorige"
}
},
"processing": true,
"serverSide": true,
"ajax": "handle/clients_processing.php",
"columnDefs": [ {
"targets": -1,
"data": null,
"defaultContent": "<a class='btn btn-info btn-xs' href='#' title='Wijzigen'><span class='glyphicon glyphicon-edit' style='margin-right:0;'></span></a>"
} ]
} );
$('#table_archive tbody').on( 'click', 'a', function () {
var data = table.row( $(this).parents('tr') ).data();
$(this).attr("href", "edit.php?id="+ data[ 4 ]);
});
Draait als een zonnetje!
Binnen 1 seconde 36.000+ rows uitgepoept.
Zal vast beter gecodeert kunnen worden, ben ik van overtuigd.
Gewijzigd op 29/09/2015 22:18:32 door Joni Fleischer
Joni Fleischer op 10/06/2015 19:59:04:
Ik heb het al!!!
Gewoon jSON uitpoepen :)
http://www.fleischer.nl/Grundfos/handlers/clients_processing.php
Nu gaat ie lekkah!
Bedankt !
Gewoon jSON uitpoepen :)
http://www.fleischer.nl/Grundfos/handlers/clients_processing.php
Nu gaat ie lekkah!
Bedankt !
Als je dit a-synchroon uitvoert, lijkt het sneller te gaan, maar dat is het niet in de praktijk. Misschien iets minder overhead door de parsing van HTML die je eerst had.
Gewoon de boel in partjes ophalen, of als iemand een bepaald record moet zoeken een auto-suggest gebruiken die met LIKE steeds verder zoekt.
Gewijzigd op 29/09/2015 23:01:52 door - Ariën -
Reageer ff op mijn andere forum bericht :P
Ik loop vast :'(