Domanda

Sto lavorando a una query per un sito di notizie, che troverà FeaturedContent da visualizzare nella home page principale. I contenuti contrassegnati in questo modo vengono contrassegnati come "Contenuti in primo piano" e ordinati in una tabella in primo piano per "home page". Al momento ho l'output desiderato, ma la query viene eseguita in oltre 3 secondi, che devo ridurre. Come si ottimizza una query come quella che segue?

MODIFICA: materializzata la visualizzazione ogni minuto come suggerito, fino a 0,4 secondi:

SELECT f.position, s.item_id, s.item_type, s.title, s.caption, s.date
FROM live.search_all s 
INNER JOIN live.tags t 
ON s.item_id = t.item_id AND s.item_type = t.item_type AND t.tag = 'FeaturedContent' 
LEFT OUTER JOIN live.featured f 
ON s.item_id = f.item_id AND s.item_type = f.item_type AND f.feature_type = 'homepage'
ORDER BY position IS NULL, position ASC, date

Restituisce in ordine tutte le funzioni della home page, seguite da altri contenuti in primo piano ordinati per data.
La spiegazione ha questo aspetto:

|-id---|-select_type-|-table-|-type---|-possible_keys---------|-key--------|-key_len-|-ref---------------------------------------|-rows--|-Extra-------------------------------------------------------------|
|-1----|-SIMPLE------|-t2----|-ref----|-PRIMARY,tag_index-----|-tag_index--|-303-----|-const-------------------------------------|-2-----|-Using where; Using index; Using temporary; Using filesort;--------|
|-1----|-SIMPLE------|-t-----|-ref----|-PRIMARY---------------|-PRIMARY----|-4-------|-newswires.t2.id---------------------------|-1974--|-Using index-------------------------------------------------------|
|-1----|-SIMPLE------|-s-----|-eq_ref-|-PRIMARY, search_index-|-PRIMARY----|-124-----|-newswires.t.item_id,newswires.t.item_type-|-1-----|-------------------------------------------------------------------|
|-1----|-SIMPLE------|-f-----|-index--|-NULL------------------|-PRIMARY----|-190-----|-NULL--------------------------------------|-13----|-Using index-------------------------------------------------------|

E il profilo è il seguente:

|-Status---------------|-Time-----|
|-starting-------------|-0.000091-|
|-Opening tables-------|-0.000756-|
|-System lock----------|-0.000005-|
|-Table lock-----------|-0.000008-|
|-init-----------------|-0.000004-|
|-checking permissions-|-0.000001-|
|-checking permissions-|-0.000001-|
|-checking permissions-|-0.000043-|
|-optimizing-----------|-0.000019-|
|-statistics-----------|-0.000127-|
|-preparing------------|-0.000023-|
|-Creating tmp table---|-0.001802-|
|-executing------------|-0.000001-|
|-Copying to tmp table-|-0.311445-|
|-Sorting result-------|-0.014819-|
|-Sending data---------|-0.000227-|
|-end------------------|-0.000002-|
|-removing tmp table---|-0.002010-|
|-end------------------|-0.000005-|
|-query end------------|-0.000001-|
|-freeing items--------|-0.000296-|
|-logging slow query---|-0.000001-|
|-cleaning up----------|-0.000007-|

Non ho mai letto l'output di EXPLAIN, quindi non sono sicuro di avere a disposizione un ordinamento migliore o qualcosa di piuttosto semplice che potrebbe essere fatto per velocizzarli.

La tabella search_all è la tabella della vista materializzata che viene aggiornata periodicamente, mentre i tag e le tabelle in primo piano sono viste. Queste visualizzazioni non sono facoltative e non possono essere aggirate.

La visualizzazione dei tag combina tag e una tabella relazionale per ottenere un elenco di tag in base a item_type e item_id, ma le altre visualizzazioni sono tutte semplici visualizzazioni di una tabella.

MODIFICA: con la vista materializzata, il collo di bottiglia più grande sembra essere il passaggio "Copia nella tabella temporanea". Senza ordinare l'output, ci vogliono 0,0025 secondi (molto meglio!) Ma l'output finale deve essere ordinato. Esiste un modo per migliorare le prestazioni di quel passaggio o aggirarlo?

Mi dispiace se la formattazione è difficile da leggere, sono nuovo e non sono sicuro di come venga eseguita regolarmente.
Grazie per l'aiuto! Se è necessario qualcos'altro, fammelo sapere!

MODIFICA: dimensioni della tabella, per riferimento:
Relazioni tag: 197,411
Tag: 16.897
Storie: 51,801
Immagini: 28.383
Video: 2,408
In primo piano: 13

È stato utile?

Soluzione

Penso che l'ottimizzazione della tua query da sola non sarà molto utile. Il primo pensiero è che l'unione di una sottoquery, a sua volta composta da UNION, è solo un doppio collo di bottiglia per le prestazioni.

Se hai la possibilità di modificare la struttura del database, ti suggerirei di unire le 3 tabelle stories, images e videos in una sola, se sono, come sembra, molto simili (aggiungendole un type ENUM('story', 'image', 'video')) per differenziarle i record; questo rimuoverà sia la sottoquery che l'unione.

Inoltre, sembra che le tue visualizzazioni su stories e videos non stiano utilizzando un campo indicizzato per filtrare il contenuto. Stai interrogando una colonna indicizzata?

È un problema piuttosto complicato senza conoscere la struttura completa della tabella e la ripartizione dei dati!

Un'altra opzione, che non comporterebbe apportare modifiche al database esistente (specialmente se è già in produzione), sarebbe quella di "memorizzare nella cache" queste informazioni in un'altra tabella, che verrebbe periodicamente aggiornata da un cron job.

La memorizzazione nella cache può essere eseguita a diversi livelli, sulla query completa o su sue sottoparti (viste indipendenti o le 3 unioni unite in un'unica tabella cache, ecc.)

La fattibilità di questa opzione dipende dal fatto che sia accettabile o meno visualizzare dati leggermente obsoleti. Potrebbe essere accettabile solo per alcune parti dei tuoi dati, il che potrebbe implicare che memorizzerai nella cache solo un sottoinsieme delle tabelle / viste coinvolte nella query.

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