Perché SQLyog restituisce risultati di query MySQL 10 volte più veloci del mio programma Delphi?

StackOverflow https://stackoverflow.com/questions/1031484

Domanda

select rectype,jobid,jobrecid,template,assignedto,entereddt,enteredby,ref1,processed,processeddt,
processbydt,title,description,connectlanhandle,finished,updateddt,ref2,cancelled,
requireaccept,acceptrejectstate,acceptrejectbydt,alert1dt,alert2dt,alert3dt,despatchallowed,
flag,ref3,projectid,duration,skillset,postcode,prefschedulefrom,prefscheduleto,customdata1,
customdata2,customdata3,hasnotes,displayjobtype,createdby,createddt,colour
 from jobs
 where updateddt >= '1982-02-05 17:25:38'
 or (processed = 'N' and
     cancelled = 'N')
 order by jobid, jobrecid

Questa query restituisce ~ 80000 risultati. SQLyog (una GUI di MySQL) può restituire i risultati in una griglia visibile in ~ 600ms. Il mio programma Delphi, che si collega usando ODBC (i driver MyODBC più recenti), impiega ~ 6000ms solo per fare la query, senza nemmeno iniziare a guardare i risultati.

Qualche idea su cosa posso fare per rendere il mio programma più veloce?

È stato utile?

Soluzione

L'ho provato da solo sulla tabella di base (nessun join) e ho trovato anche se fai clic su " Mostra tutto " casella di controllo, SQLyog non porterà immediatamente tutti i risultati sulla griglia, provalo tu stesso spostando il pulsante di scorrimento nell'area più bassa, noterai che sqlyog rallenterà per alcuni momenti e porterà più risultati da mostrare.

anche ODBC noto per essere più lento perché aggiunge più layer all'accesso nativo, quindi prova con MyDac di DevArt che utilizza l'accesso diretto a mysql (anche senza la libreria client mysql).

e, come detto soprattutto, non tentare mai di mostrare all'utente 80.000 record per volta.

A proposito, il strumenti della GUI di MySql ufficiali di Sun creato da Sun Delfi ;-)

Altri suggerimenti

La mia ipotesi è che SQLyog non abbia effettivamente visualizzato tutti gli 80.000 risultati in 600 ms - potrebbe ancora caricare quelli successivi mentre visualizza i primi. (In particolare, la maggior parte dei framework GUI che ho visto non può riempire 80.000 righe in modo rapido anche senza un database coinvolto.)

Puoi provare a fare la stessa cosa, supponendo che l'API che stai utilizzando ti consenta di ottenere risultati in modo streaming (invece di trasferire tutto in memoria prima che la chiamata ritorni).

Immagino sia perché SQLyog utilizza l'API C MySQL nativa (connessione diretta) mentre si utilizza un connettore ODBC. Hai provato connettori di terze parti come MyDAC di Devart? Puoi prendere una prova gratuita da lì e testare la tua applicazione con essa.

FWIW Uso MyDac da anni e sono davvero soddisfatto (performance / premi / supporto)

Come altri hanno già detto, è probabile perché SQLyog non sta caricando tutti i record e probabilmente lo sta limitando a circa 200.

Per risolvere questo problema di prestazioni, puoi usare trucchi subdoli. Dal momento che stai praticamente caricando una cache del set di dati nella tua applicazione all'avvio, puoi infilarlo. Il caricamento richiederebbe ancora 6 o 8 secondi, ma l'applicazione verrà comunque avviata e l'interfaccia utente sarebbe utilizzabile. Se qualcuno ha fatto qualcosa che richiedeva la cache prima che fosse caricata, potevi semplicemente visualizzare il cursore a clessidra o un messaggio che diceva "un momento per favore ..." fino a quando la cache non è pronta.

Una cosa da tenere presente quando si accede ai dati in un thread è che di solito è necessario creare una connessione al database separata nel thread. Qualcosa del genere:

type
  TLoadCacheThread = class(TThread)
  private
    FConnection : TODBCConnection; // Or whatever, I don't use ODBC :-)
    FQuery : TODBCQuery;
    FMemData : TkbmMemTable; // This is what I use, YMMV
  protected
    procedure PopulateCachedDataset;
  public
    constructor Create; override;
    procedure Execute; override;
  end;

constructor Create;
begin
  inherited Create(True); // create suspended thread
  FConnection := TODBCConnection.Create(nil);
  // Set any properties for the connection here.
  FQuery := TODBCQuery.Create(nil);
  // Set any properties for the query here.
  FQuery.SQL.Text := 'select * from mytable';
  Resume;
end;

procedure Execute;
begin
  FQuery.Open;
  FMemTable.LoadFromDataset(FQuery);
  Synchronize(PopulateCachedDataset);
end;

// The idea here is that you're loading into a mem dataset, which can then
// quickly be copied to another memory dataset, rather than loading the
// cached data directly from FQuery, which is slow and why we're threading
// in the first place. This assumes you have some kind of globalsettings unit
// or class, and it has a cacheddataset variable or property.
procedure PopulateCachedDataset;
begin
  GlobalSettings.CachedDataset.LoadFromDataset(FMemTable);
end;

Questa è l'idea di base, comunque. Esistono altri modi più complessi ma tecnicamente superiori, come fare in modo che GlobalSettings.CachedDataset carichi i dati su richiesta, quindi la prima volta che accederai sarà lento, ma i tempi successivi richiederanno più tempo, ecc. Tuttavia, dipenderà dalle tue esigenze.

HTH

È possibile utilizzare LIMIT 0,1000 su query, quindi modificarlo quando l'utente raggiunge il limite - controllando l'evento OnAfterScroll.

A mio avviso, dovresti pensare due volte alla tua applicazione e / o architettura del database - non va bene, nel gestire record da 80K. Cerca di restringere la tua query - se non ti semplificassi la vita - nessuno lo farebbe $)

Probabilmente SQLyog non caricherà tutte le 80000 righe contemporaneamente, almeno alcuni strumenti db che utilizzo eseguono "caricamento su richiesta". durante lo scorrimento. Se devi assolutamente ottenere tutti i record in una volta, considera l'utilizzo del thread per eseguire la query e popolare l'array interno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top