I'm having problems with listing and searching table data with more than 200,000 records.
I read in searches, that for the search system, the ideal would be to do indexes of the type "fulltext" in the fields where it will be will have a search for the records.
So I did it this way:
EDIT : I changed the tables by creating indexes as suggested in the comments.
Ialsoreadthelogcountforpaging,itwouldbebettertousethefunction:
SELECTFOUND_ROWS();
Ihavenotdonetheresearchpart,butI'malreadyslowtolisttherecordsaccordingtotheuser.
Ihaveanadministrativearea,whereseveraluserswillberesponsibleforregistration.Thenthesystemhastodisplayonthescreeneveryrecordthatwasmadebyaparticularuserandwithpagination.
SoIdiditthisway:
publicfunctionAdmListEmpresas($link,$usercod,$pagina=1,$ItensPorPagina=100){//Definirapartirdequantosregistroiniciaabuscadeacordocomapáginaatual.$inicio=($pagina-1)*$ItensPorPagina;$sql='SELECTSQL_NO_CACHESQL_CALC_FOUND_ROWS'empresas'.'nome','usuarios'.'nome'AS'usuarionome','equipes'.'nome'AS'equipenome','setores01'.'titulo'AS'setor01titulo','setores02'.'titulo'AS'setor02titulo','setores03'.'titulo'AS'setor03titulo','empresas'.'telprincipal','empresas'.'email','empresas'.'website','empresas'.'plantype','empresas'.'datavencimento','empresas'.'datacadastro','empresas'.'ativoinfo'FROM''.BDtables['BD_EMPRESAS'].'''empresas'LEFTJOIN''.BDtables['BD_USERS'].''AS'usuarios'ON'empresas'.'useradmcod'='usuarios'.'cod'LEFTJOIN''.BDtables['BD_USERS'].''AS'equipes'ON'empresas'.'codequiperesp'='equipes'.'cod'LEFTJOIN''.BDtables['BD_SETORES'].''AS'setores01'ON'setores01'.'cod'='empresas'.'codsetor1'LEFTJOIN''.BDtables['BD_SETORES'].''AS'setores02'ON'setores02'.'cod'='empresas'.'codsetor2'LEFTJOIN''.BDtables['BD_SETORES'].''AS'setores03'ON'setores03'.'cod'='empresas'.'codsetor3'WHERE('empresas'.'ativouser'="1" AND
'empresas'.'ativosys' = "1" AND
'empresas'.'useradmcod' = "'.$usercod.'") OR
('empresas'.'codequiperesp' = "'.$usercod.'") OR
('empresas'.'usersfunccods' LIKE "%'.$usercod.'%")
ORDER BY
'empresas'.'useradmcod' LIMIT '.$inicio.', '.$ItensPorPagina.';';
$sqlcount = 'SELECT FOUND_ROWS() as "rowcount";';
$result = $this->conn->query($sql);
$numrows = $this->conn->query($sqlcount);
$numrows = $numrows->fetch_array(MYSQLI_ASSOC);
if ($result->num_rows >= 1) {
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$listaarray[] = ['empresa' => $row['nome'],
'usuarionome' => $row['usuarionome'],
'equipenome' => $row['equipenome'],
'setor01titulo' => $row['setor01titulo'],
'setor02titulo' => $row['setor02titulo'],
'setor03titulo' => $row['setor03titulo'],
'telprincipal' => $row['telprincipal'],
'email' => $row['email'],
'website' => $row['website'],
'plantype' => $row['plantype'],
'datavencimento' => $row['datavencimento'],
'datacadastro' => $row['datacadastro'],
'ativoinfo' => $row['ativoinfo']
];
}
}
if (empty($listaarray)) { $listaarray = false; }
// Array da Paginação
$paginacaoarray = $this->Paginacao($link, $numrows['rowcount'], $pagina, $ItensPorPagina);
return array('paginacao' => $paginacaoarray,'lista' => $listaarray);
}
The BD_EMPRESAS table has the registration of all companies with more than 200 thousand records.
The BD_USERS table can also contain more than 200,000 records, and in the business listing, you may have to search the user IDs to find the name of each.
The BD_SETORES table will have a small table of 300 records, and each company will have up to 3 sectors, where in the search it must get the name of each sector according to the ID.In WHERE in the query, you get the user code logged in, and search for it between 3 table fields where it can be the administrator, system team, or company employee. Then a search of all companies that that user participates is done, being able to return in average of 5 thousand registries in this list. Where pagination will display 200 to 200 records. (I had no problems with the paging, only with the time to delay the return of the records).
In WHERE , the ativouser
and ativosys
fields are only for searching the records that are active, listed as a enum
field that stores 0 for disabled and 1 for enabled . The q returns only the enabled companies, but a super administrator will also have to list the disabled logs which can further increase the number of registrations displayed.
All this is then stored in an Array where it is sent to another area of the php that displays the results inside a template compiled by a smarty type system.
Anyone who has ever worked with giant tables could help me with a better solution ??
EDIT 01:
As suggested by @bfavaretto, below is the result of EXPLAIN
:
EDITED 02: I did some tests here, the query the way you are with limit displaying 200 of 200 records, it takes 7 seconds for each query.
I noticed that SQL_CALC_FOUND_ROWS is very heavy on the query, it alone takes more JOINS than it does with the JOINS.
If I leave the JOINS but retire the SQL_CALC_FOUND_ROWS, 7 seconds down for 4 or 5 seconds.
If I remove SQL_CALC_FOUND_ROWS and JOINS the query goes for less than 1 second, which would be perfect.
The problem is that I need the JOINS to display the results on the screens. Now I need to think about a way to replace JOINS and display the same results.