Come estendere WP_Query per includere una tabella personalizzata nella query?
Sono giorni che affronto questo problema. Inizialmente si trattava di come memorizzare i dati dei follower di un utente nel database, per il quale ho ricevuto un paio di buoni suggerimenti qui su WordPress Answers. Seguendo i suggerimenti, ho aggiunto una nuova tabella così strutturata:
id leader_id follower_id
1 2 4
2 3 10
3 2 10
Nella tabella sopra, la prima riga ha un utente con ID 2 che viene seguito da un utente con ID 4. Nella seconda riga, un utente con ID 3 viene seguito da un utente con ID 10. La stessa logica si applica alla terza riga.
Ora, essenzialmente voglio estendere WP_Query in modo da poter limitare i post recuperati solo a quelli dei leader di un utente. Quindi, considerando la tabella sopra, se dovessi passare l'ID utente 10 a WP_Query, i risultati dovrebbero contenere solo i post degli utenti con ID 2 e ID 3.
Ho cercato molto cercando di trovare una risposta. Non ho trovato nessun tutorial per aiutarmi a capire come estendere la classe WP_Query. Ho visto le risposte di Mike Schinkel (sull'estensione di WP_Query) a domande simili, ma non ho davvero capito come applicarle alle mie esigenze. Sarebbe fantastico se qualcuno potesse aiutarmi con questo.

Importante avviso: il modo corretto per farlo NON è modificare la struttura della tabella, ma utilizzare wp_usermeta. In questo modo non sarà necessario creare SQL personalizzati per interrogare i post (anche se potrebbe servire comunque un SQL personalizzato per ottenere un elenco di tutti coloro che rispondono a un determinato supervisore - nella sezione Admin, ad esempio). Tuttavia, visto che l'OP ha chiesto come scrivere SQL personalizzati, ecco le migliori pratiche attuali per iniettare SQL personalizzati in una query esistente di WordPress.
Se stai facendo join complessi, non puoi semplicemente usare il filtro posts_where, perché dovrai modificare anche il join, il select e possibilmente le sezioni group by o order by della query.
La soluzione migliore è usare il filtro 'posts_clauses'. Questo è un filtro estremamente utile (che non dovrebbe essere abusato!) che ti permette di aggiungere/modificare le varie parti dell'SQL generato automaticamente dalle moltissime righe di codice nel core di WordPress. La firma del callback del filtro è:
function posts_clauses_filter_cb( $clauses, $query_object ){ }
e si aspetta che tu restituisca $clauses
.
Le Clausole
$clauses
è un array che contiene le seguenti chiavi; ogni chiave è una stringa SQL che verrà usata direttamente nell'istruzione SQL finale inviata al database:
- where
- groupby
- join
- orderby
- distinct
- fields
- limits
Se stai aggiungendo una tabella al database (fallo solo se assolutamente non puoi usare post_meta, user_meta o tassonomie) probabilmente dovrai toccare più di una di queste clausole, ad esempio fields
(la parte "SELECT" dell'istruzione SQL), join
(tutte le tue tabelle, oltre a quella nella clausola "FROM"), e forse orderby
.
Modificare le Clausole
Il modo migliore per farlo è fare riferimento alla chiave rilevante dall'array $clauses
che hai ottenuto dal filtro:
$join = &$clauses['join'];
Ora, se modifichi $join
, modificherai direttamente $clauses['join']
quindi le modifiche saranno presenti in $clauses
quando lo restituirai.
Preservare le Clausole Originali
È probabile (no, sul serio, ascolta) che tu voglia preservare l'SQL esistente generato da WordPress. Altrimenti, dovresti probabilmente guardare il filtro posts_request
invece - che è la query mySQL completa appena prima che venga inviata al database, quindi puoi completamente sovrascriverla con la tua. Perché vorresti farlo? Probabilmente non vorresti.
Quindi, per preservare l'SQL esistente nelle clausole, ricordati di aggiungere alle clausole, non di assegnarle (es: usa $join .= ' {NUOVO SQL}';
non $join = '{SOVRASCRIVI SQL}';
. Nota che poiché ogni elemento dell'array $clauses
è una stringa, se vuoi aggiungere, probabilmente dovrai inserire uno spazio prima di qualsiasi altro token di caratteri, altrimenti potresti creare qualche errore di sintassi SQL.
Puoi semplicemente assumere che ci sarà sempre qualcosa in ognuna delle clausole, e quindi ricordati di iniziare ogni nuova stringa con uno spazio, come in: $join .= ' my_table
, oppure puoi sempre aggiungere una piccola riga che aggiunge uno spazio solo se necessario:
$join = &$clauses['join'];
if (! empty( $join ) ) $join .= ' ';
$join .= "JOIN my_table... "; // <-- nota lo spazio alla fine
$join .= "JOIN my_other_table... ";
return $clauses;
Questa è più una questione di stile che altro. La cosa importante da ricordare è: lascia sempre uno spazio PRIMA della tua stringa se stai aggiungendo a una clausola che ha già dell'SQL!
Mettendo tutto insieme
La prima regola dello sviluppo WordPress è cercare di usare il più possibile le funzionalità del core. Questo è il modo migliore per rendere il tuo lavoro futuro-proof. Supponiamo che il core team decida che WordPress utilizzerà ora SQLite o Oracle o qualche altro linguaggio di database. Qualsiasi mySQL scritto a mano potrebbe diventare invalido e rompere il tuo plugin o tema! Meglio lasciare che WP generi da solo più SQL possibile, e aggiungere solo i pezzi che ti servono.
Quindi il primo ordine di business è sfruttare WP_Query
per generare più possibile della tua query base. Il metodo esatto che usiamo per farlo dipende in gran parte da dove questa lista di post dovrebbe apparire. Se è una sotto-sezione della pagina (non la tua query principale) useresti get_posts()
; se è la query principale, suppongo che potresti usare query_posts()
e finirla lì, ma il modo corretto per farlo è intercettare la query principale prima che arrivi al database (e consumi cicli del server) quindi usa il filtro request
.
Ok, quindi hai generato la tua query e l'SQL sta per essere creato. Beh, in realtà, è già stato creato, solo non inviato al database. Usando il filtro posts_clauses
, aggiungerai la tua tabella delle relazioni dei dipendenti nel mix. Chiamiamo questa tabella {$wpdb->prefix} . 'user_relationship', ed è una tabella di intersezione. (A proposito, ti consiglio di generalizzare questa struttura di tabella e trasformarla in una vera tabella di intersezione con i seguenti campi: 'relationship_id', 'user_id', 'related_user_id', 'relationship_type'; questo è molto più flessibile e potente... ma sto divagando).
Se ho capito bene quello che vuoi fare, vuoi passare l'ID di un Leader e poi vedere solo i post dei Follower di quel Leader. Spero di aver capito bene. Se non è corretto, dovrai adattare quello che dico alle tue esigenze. Mi atterrò alla tua struttura di tabella: abbiamo un leader_id
e un follower_id
. Quindi il JOIN sarà su {$wpdb->posts}.post_author
come chiave esterna al 'follower_id' sulla tua tabella 'user_relationship'.
add_filter( 'posts_clauses', 'filter_by_leader_id', 10, 2 ); // abbiamo bisogno del 2 perché vogliamo ottenere tutti gli argomenti
function filter_by_leader_id( $clauses, $query_object ){
// Non so come intendi passare il leader_id, quindi supponiamo sia un globale
global $leader_id;
// In questo esempio voglio influenzare solo una query nella home page.
// Qui viene usato $query_object, per aiutarci a evitare di influenzare
// TUTTE le query (poiché TUTTE le query passano attraverso questo filtro)
if ( $query_object->is_home() ){
// Ora, aggiungiamo la tua tabella nell'SQL
$join = &$clauses['join'];
if (! empty( $join ) ) $join .= ' '; // aggiungi uno spazio solo se necessario (per i punti bonus!)
$join .= "JOIN {$wpdb->prefix}employee_relationship EMP_R ON EMP_R.follower_id = {$wpdb->posts}.author_id";
// E assicuriamoci di aggiungerlo ai nostri criteri di selezione
$where = &$clauses['where'];
// In ogni caso, inizi sempre con AND, perché c'è sempre un'istruzione '1=1' come prima istruzione della clausola WHERE che viene aggiunta da WP/
// Solo non dimenticare lo spazio iniziale!
$where .= " AND EMP_R.leader_id={$leader_id}"; // assumendo che $leader_id sia sempre (int)
// E suppongo che vorrai i post "raggruppati" per id utente, quindi modifichiamo la clausola groupby
$groupby = &$clauses['groupby'];
// Dobbiamo prependere, quindi...
if (! empty( $groupby ) ) $groupby = ' ' . $groupby; // Per i gradassi
$groupby = "{$wpdb->posts}.post_author" . $groupby;
}
// In ogni caso, dobbiamo restituire le nostre clausole...
return $clauses;
}

Rispondo a questa domanda con molto ritardo e mi scuso per questo. Sono stato estremamente occupato con scadenze lavorative e non ho potuto dedicarmi a questo prima.
Un grande grazie a @m0r7if3r e @kaiser per aver fornito le soluzioni di base che ho potuto estendere e implementare nella mia applicazione. Questa risposta fornisce dettagli sulla mia adattamento delle soluzioni offerte da @m0r7if3r e @kaiser.
Innanzitutto, lasciatemi spiegare perché ho posto questa domanda. Dalla domanda e dai relativi commenti si può capire che sto cercando di far sì che WP_Query recuperi i post di tutti gli utenti (leader) che un determinato utente (follower) segue. La relazione tra follower e leader è memorizzata in una tabella personalizzata follow
. La soluzione più comune a questo problema è recuperare gli ID utente di tutti i leader di un follower dalla tabella follow e inserirli in un array. Vedere sotto:
global $wpdb;
$results = $wpdb->get_results($wpdb->prepare('SELECT leader_id FROM cs_follow WHERE follower_id = %s', $user_id));
foreach($results as $result)
$leaders[] = $result->leader_id;
Una volta ottenuto l'array dei leader, puoi passarlo come argomento a WP_Query. Vedi sotto:
if (isset($leaders)) $authors = implode(',', $leaders); // Necessario poiché l'argomento authors di WP_Query accetta solo stringhe contenenti ID degli autori separati da virgole
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'author' => $authors
);
$wp_query = new WP_Query( $args );
// Il normale loop di WordPress continua
La soluzione sopra è il modo più semplice per ottenere i risultati desiderati. Tuttavia, non è scalabile. Nel momento in cui hai un follower che segue decine di migliaia di leader, l'array risultante di ID leader diventerebbe estremamente grande e costringerebbe il tuo sito WordPress a utilizzare 100MB - 250MB di memoria per ogni caricamento di pagina, eventualmente causando il crash del sito. La soluzione al problema è eseguire una query SQL direttamente sul database e recuperare i post rilevanti. È qui che la soluzione di @m0r7if3r è venuta in soccorso. Seguendo la raccomandazione di @kaiser, ho deciso di testare entrambe le implementazioni. Ho importato circa 47K utenti da un file CSV per registrarli su una nuova installazione di prova di WordPress. L'installazione utilizzava il tema Twenty Eleven. Successivamente, ho eseguito un ciclo for per fare in modo che circa 50 utenti seguissero tutti gli altri utenti. La differenza nel tempo di query per entrambe le soluzioni di @kaiser e @m0r7if3r è stata sorprendente. La soluzione di @kaiser richiedeva normalmente circa 2-5 secondi per ogni query. La variazione presumo avvenga poiché WordPress memorizza nella cache le query per un uso successivo. D'altra parte, la soluzione di @m0r7if3r ha dimostrato un tempo medio di query di 0,02 ms. Per testare entrambe le soluzioni, avevo l'indicizzazione attiva per la colonna leader_id. Senza indicizzazione, c'è stato un drammatico aumento del tempo di query.
L'utilizzo della memoria con la soluzione basata su array si attestava intorno ai 100-150 MB e scendeva a 20 MB quando si eseguiva una SQL diretta.
Ho incontrato un problema con la soluzione di @m0r7if3r quando ho avuto bisogno di passare l'ID del follower alla funzione del filtro posts_where. Per quanto ne sappia, WordPress non consente alcun mezzo per passare una variabile alle funzioni di filtro. Puoi usare variabili globali, ma volevo evitarle. Alla fine ho esteso WP_Query per risolvere definitivamente il problema. Quindi ecco la soluzione finale che ho implementato (basata sulla soluzione di @m0r7if3r).
class WP_Query_Posts_by_Leader extends WP_Query {
var $follower_id;
function __construct($args=array()) {
if(!empty($args['follower_id'])) {
$this->follower_id = $args['follower_id'];
add_filter('posts_where', array($this, 'posts_where'));
}
parent::query($args);
}
function posts_where($where) {
global $wpdb;
$table_name = $wpdb->prefix . 'follow';
$where .= $wpdb->prepare(" AND post_author IN (SELECT leader_id FROM " . $table_name . " WHERE follower_id = %d )", $this->follower_id);
return $where;
}
}
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'follower_id' => $follower_id
);
$wp_query = new WP_Query_Posts_by_Leader( $args );
Nota: Alla fine ho provato la soluzione sopra con 1,2 milioni di voci nella tabella follow. Il tempo medio di query si è attestato intorno a 0,060 ms.

Puoi farlo con una soluzione interamente SQL utilizzando il filtro posts_where
. Ecco un esempio:
if( qualche condizione )
add_filter( 'posts_where', 'wpse50305_leader_where' );
// lol, l'ID della domanda è lo stesso avanti e indietro
function wpse50305_leader_where( $where ) {
$where .= $GLOBALS['wpdb']->prepare( ' AND post_author '.
'IN ( '.
'SELECT leader_id '.
'FROM custom_table_name '.
'WHERE follower_id = %s'.
' ) ', $follower_id );
return $where;
}
Penso che ci possa essere un modo per farlo anche con JOIN
, ma non riesco a trovare una soluzione. Continuerò a sperimentare e aggiornerò la risposta se ci riuscirò.
In alternativa, come suggerito da @kaiser, puoi dividerlo in due parti: ottenere i leader e fare la query. Ho la sensazione che questo potrebbe essere meno efficiente, ma è sicuramente il modo più comprensibile. Dovresti testare l'efficienza per determinare quale metodo è migliore, poiché le query SQL annidate possono diventare piuttosto lente.
DAL COMMENTI:
Dovresti inserire la funzione nel tuo functions.php
e fare l'add_filter()
subito prima che venga chiamato il metodo query()
di WP_Query
. Subito dopo, dovresti usare remove_filter()
in modo che non influisca sulle altre query.

Ho modificato il tuo A e aggiunto prepare()
. Spero non ti dispiaccia la modifica. E sì: le prestazioni devono essere misurate dall'OP. Comunque: penso ancora che questo dovrebbe essere semplicemente usermeta e nient'altro.

@m0r7if3r Grazie per aver provato a trovare una soluzione. Ho appena pubblicato un commento in risposta alla risposta di kaiser, con preoccupazioni su possibili problemi di scalabilità. Ti prego di prenderlo in considerazione.

@m0r7if3r Stavo testando questo e ho scoperto che fa sì che WP_Query restituisca tutti i post. Con tutti i post intendo post di tutti i tipi (post, allegati, pagine) di tutti gli utenti. Questa è la SQL che echo $wp_query->request;
restituisce per la query SQL_CALC_FOUND_ROWS cs_posts.* FROM cs_posts INNER JOIN cs_postmeta ON (cs_posts.ID = cs_postmeta.post_id) WHERE 1=1 GROUP BY cs_posts.ID ORDER BY cs_posts.post_date DESC LIMIT 0, 30

Mi sono dimenticato di return $where;
. Il codice aggiornato risolve il problema?

Accidenti! Quei refusi. Sì, ora funziona. Proverò a implementare la soluzione di @kaiser e misurare i tempi. A proposito, un effetto collaterale che ho notato usando questo metodo è che inizia a influenzare tutte le query se ce ne sono molte in una singola pagina. Inoltre, questo ha interrotto il rewrite degli URL per me quando inserito in function.php. Spostando il codice appena sopra la chiamata WP_Query si è risolto il problema con il rewrite degli URL. Ma non sono sicuro se posizionarlo sopra WP_Query sia una cattiva pratica???

Dovresti inserire la funzione nel tuo functions.php
e fare add_filter()
subito prima che venga chiamato il metodo query()
di WP_Query
. Immediatamente dopo, dovresti fare remove_filter()
in modo che non influenzi le altre query. Non sono sicuro di quale sia il problema con il rewrite degli URL, ho usato posts_where
molte volte e non ho mai visto quel problema...

@m0r7if3r Grazie per avermelo fatto notare. Proseguo con i test sui dati di esempio. Ti terrò aggiornato.

@m0r7if3r Il tuo ultimo commento sarebbe perfetto come citazione all'interno della Q :)

Tag del Template
Inserisci entrambe le funzioni nel tuo file functions.php
. Poi modifica la prima funzione e aggiungi il nome della tua tabella personalizzata. Dovrai fare qualche prova/errore per eliminare l'ID dell'utente corrente dall'array risultante (vedi commento).
/**
* Ottieni i "Leader" dell'utente corrente
* @param int $user_id L'ID dell'utente corrente
* @return array $query I leader
*/
function wpse50305_get_leaders( $user_id )
{
global $wpdb;
return $wpdb->query( $wpdb->prepare(
"
SELECT `leader_id`, `follower_id`
FROM %s
WHERE `follower_id` = %s
ORDERBY `leader_id` ASC
",
// Modifica il nome della tabella
"{$wpdb->prefix}custom_table_name"
$user_id
) );
}
/**
* Ottieni un array di post che contengono articoli scritti dai
* "Leader" seguiti dall'utente corrente
* @return array $posts Post scritti dal "Leader" corrente
*/
function wpse50305_list_posts_by_leader()
{
get_currentuserinfo();
global $current_user;
$user_id = $current_user->ID;
$leaders = wpse5035_get_leaders( $user_id );
// potrebbe essere necessario ciclare su $leaders
// per rimuovere gli ID dei follower
return get_posts( array(
'author' => implode( ",", $leaders )
) );
}
All'interno del template
Qui puoi fare ciò che vuoi con i risultati ottenuti.
foreach ( wpse50305_list_posts_by_leader() as $post )
{
// fai qualcosa con $post
}
NOTA Non abbiamo dati di test, ecc. quindi quanto sopra è un po' un'ipotesi. Assicurati di modificare questa risposta con ciò che ha funzionato per te, così avremo un risultato soddisfacente per i lettori futuri. Approverò la modifica nel caso tu abbia un reputation troppo bassa. Potrai poi anche cancellare questa nota. Grazie.

Grazie per aver fornito una soluzione. Tuttavia, questo approccio presenta delle limitazioni in termini di scalabilità. Il problema risiede nel recuperare gli ID dei leader come un array. L'array potrebbe diventare estremamente grande a seconda del numero di utenti seguiti da un utente. Ho visto questo metodo consumare grandi quantità di memoria. Questo dovrebbe essere fatto come una singola query SQL che potrebbe coinvolgere un join tra la tabella personalizzata e la tabella dei post di WP e recuperare i risultati. La soluzione migliore è estendere WP_Query. Il problema è che non so come farlo. Ancora grazie per il tentativo. Feedback ben accetti.

JOIN
è molto più costoso. Inoltre: Come ho detto, non abbiamo dati di test, quindi per favore prova entrambe le soluzioni e illuminaci con i tuoi risultati.

WP_Query stesso lavora con JOIN tra la tabella dei post e la postmeta quando interroga. Ho visto l'utilizzo della memoria PHP salire a 70MB - 200MB per caricamento di pagina. Eseguire qualcosa del genere con molti utenti simultanei richiederebbe un'infrastruttura estrema. La mia ipotesi è che, dato che WordPress implementa già una tecnica simile, i JOIN dovrebbero essere meno gravosi rispetto a lavorare con un array di ID.

No, scusa, ma no. Ci sono anche tentativi di eliminare ulteriori JOIN
. Ad esempio: WP aggiunge un JOIN
della tabella dei termini quando si eseguono query per più tassonomie, il che è controproducente per le prestazioni. Basta usare timer_start()
prima della query e timer_stop()
dopo la query per misurare la differenza.

Inoltre: Assicurati di avere l'INDEX
sulla colonna corretta. Questo fa un'enorme differenza nelle prestazioni. In un progetto che ho realizzato, dove dovevo eseguire query per latitudine/longitudine, ho una tabella aggiuntiva piccola, ben indicizzata e che performa molto più velocemente di qualsiasi JOIN
abbia provato. Per approfondire la conoscenza sui JOIN
, leggi questo.

Quindi il tuo consiglio sarebbe di rimanere con l'array piuttosto che eseguire una SQL con join, corretto?

Sì, ma come ha detto @m0r7if3r: misuralo. Ti ho fornito i link. Devi solo cronometrarlo e mostrarci cosa ne hai ricavato. Se non lo fai, beh allora abbiamo fatto un bel po' di supposizioni :)

Sto sicuramente provando entrambe le soluzioni. Ma, per cronometrare questo, dovrò scaricare il database con dati di test, il che richiederà alcune ore (popolerò il db con 50k utenti). Lo farò e vi terrò aggiornati.

Ok ecco i risultati del test. Per questo ho aggiunto circa 47K utenti da un file csv. Successivamente, ho eseguito un ciclo for per fare in modo che i primi 45 utenti seguissero tutti gli altri utenti. Questo ha portato a 3,704,951 record salvati nella mia tabella personalizzata. Inizialmente, la soluzione di @m0r7if3r mi dava un tempo di query di 95 secondi, che è sceso a 0.020 ms dopo aver attivato l'indicizzazione sulla colonna leader_id. La memoria PHP totale consumata era di circa 20MB. D'altra parte, la tua soluzione ha impiegato circa 2-5 secondi per la query con l'indicizzazione attiva. La memoria PHP totale consumata era di circa 117MB.

@John Potresti per favore aggiungerlo come risposta separata? Sono davvero contento che tu abbia fatto questo test e ci abbia fornito dati reali. :) Quello che apprezzerei ancora di più è un test più "realistico": Fai sì che ogni utente segua un$leader_amount = rand( 0, 5 );e poi aggiungi il numero di
$leader_amountx
$random_ids = rand( 0, 47000 );` per ogni utente. Finora quello che sappiamo è: La mia soluzione sarebbe estremamente negativa se un utente seguisse tutti gli altri utenti. Inoltre: Dovrai mostrare come hai fatto il test e dove esattamente hai aggiunto i timer. Questa è una domanda unica e mi piace molto :)

@John Ho linkato e condiviso la tua domanda e partecipazione e volevo far notare che tutti apprezzano molto il tuo lavoro su questo (vedi i voti positivi). :)

Eseguirò ulteriori test basandomi sul tuo suggerimento per effettuare un test più realistico e successivamente scriverò una risposta con i dettagli. Tuttavia, per un vero test reale ci sono altre due variabili che attualmente non posso simulare. Primo: Almeno 20 post per ogni utente. Attualmente, ho testato solo con circa 50 post tra 2-3 utenti. Secondo: Un traffico elevato. Queste due variabili influenzerebbero anche i risultati ottenuti nella vita reale.

Stavo ancora esaminando il tuo suggerimento di randomizzare il seguente. Tuttavia, non sono riuscito a capire i frammenti di codice che hai scritto. Uno snippet completo sarebbe più utile. Questo è ciò che ho fatto per far sì che i primi 50 utenti seguano tutti gli altri: for ($j = 2; $j <= 52; $j++) { for ($i = ($j + 1); $i <= 47000; $i++) { $rows_affected = $wpdb->insert($table_name, array( 'leader_id' => $i, 'follower_id' => $j)); } }
. Un semplice ciclo for annidato.

Sul traffico) Potresti usare le ultime versioni di Apache, Nginx, minificazione, caching, compressione, ecc. Ognuna di queste avrebbe un impatto sui risultati. Ma noi cerchiamo risultati in un ambiente locale, base (senza plugin, tema predefinito) che possa davvero essere valutato.

Hai ricevuto una notifica per il mio commento riguardo la randomizzazione? Credo di aver dimenticato di menzionare il tuo handle nel commento. Comunque, immagino che il proprietario del post sia stato notificato. Aspetterò il tuo feedback prima di procedere.

Nota: Questa risposta è qui per evitare discussioni prolungate nei commenti
Ecco il codice dell'OP dai commenti, per aggiungere il primo set di utenti di test. Deve essere modificato per un esempio reale.
for ( $j = 2; $j <= 52; $j++ ) { for ( $i = ($j + 1); $i <= 47000; $i++ ) { $rows_affected = $wpdb->insert( $table_name, array( 'leader_id' => $i, 'follower_id' => $j ) ); } }
OP Sul Test Per questo ho aggiunto circa 47K utenti da un file csv. Poi, ho eseguito un ciclo for per far sì che i primi 45 utenti seguissero tutti gli altri utenti.
- Questo ha portato a 3.704.951 record salvati nella mia tabella personalizzata.
- Inizialmente, la soluzione di @m0r7if3r mi dava un tempo di query di 95 sec, sceso a 0.020 ms dopo aver attivato l'indicizzazione sulla colonna leader_id. La memoria PHP totale consumata era di circa 20MB.
- D'altra parte, la tua soluzione ha impiegato circa 2-5 sec per la query con l'indicizzazione attiva. La memoria PHP totale consumata era di circa 117MB.
La mia risposta a questo ↑ test:
un test più "realistico": Fai sì che ogni utente segua un
$leader_amount = rand( 0, 5 );
e poi aggiungi il numero di$leader_amount x $random_ids = rand( 0, 47000 );
a ogni utente. Finora sappiamo che: La mia soluzione sarebbe estremamente pessima se un utente seguisse tutti gli altri utenti. Inoltre: Dovresti mostrare come hai fatto il test e dove esattamente hai aggiunto i timer.Devo anche precisare che il ↑ tracking del tempo sopra non può essere realmente misurato, poiché includerebbe anche il tempo per calcolare il ciclo. Sarebbe meglio scorrere il set risultante di ID in un secondo ciclo.
ulteriore processo qui

Nota per coloro che hanno seguito questa domanda: sono in procinto di misurare le prestazioni in varie condizioni e pubblicherò i risultati tra 1 o 3 giorni. Questo compito è stato estremamente dispendioso in termini di tempo a causa della quantità di dati di test che devono essere generati.
