Domanda

Dato che questo è il mio primo post mi sembra che possa pubblicare solo 1 link in modo ho elencato i siti mi riferisco alla parte inferiore. In poche parole il mio obiettivo è quello di rendere il database restituisce i risultati più veloce, ho cercato di includere tutte le informazioni rilevanti, come ho potuto pensare di aiuto cornice le domande al fondo al post.

Macchina Info


8 processors
model name      : Intel(R) Xeon(R) CPU           E5440  @ 2.83GHz
cache size      : 6144 KB
cpu cores       : 4 

top - 17:11:48 up 35 days, 22:22, 10 users,  load average: 1.35, 4.89, 7.80
Tasks: 329 total,   1 running, 328 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 87.4%id, 12.5%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   8173980k total,  5374348k used,  2799632k free,    30148k buffers
Swap: 16777208k total,  6385312k used, 10391896k free,  2615836k cached

Tuttavia stiamo esaminando spostando l'installazione mysql ad una macchina differente del cluster che ha 256 GB di ram

Tabella Info


Il mio MySQL Table appare come

CREATE TABLE ClusterMatches 
(
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    cluster_index INT, 
    matches LONGTEXT,
    tfidf FLOAT,
    INDEX(cluster_index)   
);

Ha circa 18M righe, ci sono 1M di cluster_index unica e 6K corrispondenze univoche. La query SQL che sto generando in PHP assomiglia.

query SQL


$sql_query="SELECT `matches`,sum(`tfidf`) FROM 
(SELECT * FROM Test2_ClusterMatches WHERE `cluster_index` in (".$clusters.")) 
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) DESC LIMIT 0, 10;";

dove $ cluster contiene una stringa di circa 3.000 separati da virgole di cluster_index. Questa interrogazione si avvale di circa 50.000 righe e richiede circa 15s per eseguire, quando la stessa query si esegue nuovamente occorre circa 1S eseguire.

Uso


  1. Il contenuto della tabella può essere considerata statica.
  2. basso numero di utenti simultanei
  3. La query sopra è attualmente l'unica domanda che verrà eseguito sul tavolo

sottoquery


In base a questo post [StackOverflow: cache / riutilizzare una sottoquery in MySQL]. [1] e il miglioramento nel tempo della query Credo che la mia subquery possono essere indicizzati

mysql> EXPLAIN EXTENDED SELECT `matches`,sum(`tfidf`) FROM 
(SELECT * FROM ClusterMatches WHERE `cluster_index` in (1,2,...,3000) 
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) ASC LIMIT 0, 10;

+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
| id | select_type | table                | type  | possible_keys | key           | key_len | ref  | rows  | Extra                           |
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
|  1 | PRIMARY     |  derived2            | ALL   | NULL          | NULL          | NULL    | NULL | 48528 | Using temporary; Using filesort | 
|  2 | DERIVED     | ClusterMatches       | range | cluster_index | cluster_index | 5       | NULL | 53689 | Using where                     | 
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+

In base a questo articolo vecchio [Ottimizzazione di MySQL: Query e indici] [2] nelle informazioni extra - i cattivi da vedere qui sono "utilizzando temporaneo" e "utilizzando FileSort"

MySQL Configurazione Info


La cache di query è disponibile, ma efficace spento come la dimensione è attualmente impostato a zero


mysqladmin variables;
+---------------------------------+----------------------+
| Variable_name                   | Value                |
+---------------------------------+----------------------+
| bdb_cache_size                  | 8384512              | 
| binlog_cache_size               | 32768                | 
| expire_logs_days                | 0                    |
| have_query_cache                | YES                  | 
| flush                           | OFF                  |
| flush_time                      | 0                    |
| innodb_additional_mem_pool_size | 1048576              |
| innodb_autoextend_increment     | 8                    |
| innodb_buffer_pool_awe_mem_mb   | 0                    |
| innodb_buffer_pool_size         | 8388608              |
| join_buffer_size                | 131072               |
| key_buffer_size                 | 8384512              |
| key_cache_age_threshold         | 300                  |
| key_cache_block_size            | 1024                 |
| key_cache_division_limit        | 100                  |
| max_binlog_cache_size           | 18446744073709547520 | 
| sort_buffer_size                | 2097144              |
| table_cache                     | 64                   | 
| thread_cache_size               | 0                    | 
| query_cache_limit               | 1048576              |
| query_cache_min_res_unit        | 4096                 |
| query_cache_size                | 0                    |
| query_cache_type                | ON                   |
| query_cache_wlock_invalidate    | OFF                  |
| read_rnd_buffer_size            | 262144               |
+---------------------------------+----------------------+

In base a questo articolo sul [Mysql Database Performance di svolta] [3] Credo che i valori che ho bisogno di modificare sono

  1. table_cache
  2. key_buffer
  3. sort_buffer
  4. read_buffer_size
  5. record_rnd_buffer (per GROUP BY e ORDER BY termini)

aree individuate per il miglioramento - MySQL Query tweaks


  1. Modifica del tipo di dati per le partite di un indice che è un int punta a un'altra tabella [MySQL infatti utilizzare un formato di riga dinamica se contiene campi di lunghezza variabile come TEXT o BLOB, che, in questo caso, mezzi ordinamento necessità di essere fatto su disco. La soluzione non è di astenersi questi tipi di dati, ma piuttosto di scindere tali campi in una tabella associata.] [4]
  2. L'indicizzazione del nuovo match_index feild in modo che il GROUP BY matches si verifica più veloce, basato sulla dichiarazione [ "Probabilmente si dovrebbe creare indici per tutto il campo su cui si sta selezionando, di raggruppamento, ordinamento, o raggiungano."] [5]

Strumenti


Per eseguire ritocco Ho intenzione di utilizzare

  1. [spiegare] [6] facendo riferimento [il formato di uscita] [7]
  2. [ab - strumento di analisi comparativa server Apache HTTP] [8]
  3. [Profiling] [9] con [i dati di log] [10]

Futuro Dimensioni database


L'obiettivo è quello di costruire un sistema che può avere 1M valori cluster_index unica 1M valori corrispondenza univoca, circa 3 miliardi righe della tabella con un tempo di risposta alla query di circa 0,5s (possiamo aggiungere più RAM, se necessario e distribuire il database su il cluster)

Domande


  1. Penso che vogliamo mantenere l'intero set di record nella RAM in modo che la query doesnt toccare il disco, se osserviamo l'intero database nella cache di MySQL fa che eliminano la necessità di memcachedb?
  2. sta cercando di mantenere l'intero database MySQL nella cache una cattiva strategia come la sua non progettato per essere persistente? Sarebbe qualcosa di simile memcachedb o Redis essere un approccio migliore, in caso affermativo perché?
  3. è la tabella temporanea "risultato" che viene creato dalla query distrutto automaticamente quando termina di query?
  4. dovremmo passare da InnoDB di MyISAM [come la sua buona per la lettura pesante data dove come InnoDB è un bene per pesante scrittura] [11]?
  5. la cache doesnt sembrano essere su come il suo zero nella mia [Configurazione cache delle query] [12], perché la query attualmente si verificano più veloce la seconda volta che l'eseguo?
  6. Posso ristrutturare la mia domanda per eliminare "utilizzando temporaneo" e "utilizzando FileSort" si verificano, dovrei usare un join invece di una sottoquery?
  7. come si fa a visualizzare la dimensione del MySQL [Data Cache] [13]?
  8. che tipo di dimensioni per i valori table_cache, key_buffer, sort_buffer, read_buffer_size, record_rnd_buffer suggeriresti come punto di partenza?

Link


  • 1: stackoverflow.com/questions/658937/cache-re-use-a-subquery-in-mysql
  • 2: databasejournal.com/features/mysql/article.php/10897_1382791_4/Optimizing-MySQL-Queries-and-Indexes.htm
  • 3: debianhelp.co.uk/mysqlperformance.htm
  • 4: 20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck /
  • 5: 20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck /
  • 6: dev.mysql.com/doc/refman/5.0/en/explain.html
  • 7: dev.mysql.com/doc/refman/5.0/en/explain-output.html
  • 8: httpd.apache.org/docs/2.2/programs/ab.html
  • 9: mtop.sourceforge.net /
  • 10: dev.mysql.com/doc/refman/5.0/en/slow-query-log.html
  • 11: 20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck /
  • 12: dev.mysql.com/doc/refman/5.0/en/query-cache-configuration.html
  • 13: dev.mysql.com/tech-resources/articles/mysql-query-cache.html
È stato utile?

Soluzione

Modifica della tabella


Sulla base del parere in questo post su Come scegliere gli indici per ORDER bY e GROUP bY query tabella ora sembra

CREATE TABLE ClusterMatches 
(
    cluster_index INT UNSIGNED, 
    match_index INT UNSIGNED,
    id INT NOT NULL AUTO_INCREMENT,
    tfidf FLOAT,
    PRIMARY KEY (match_index,cluster_index,id,tfidf)
);
CREATE TABLE MatchLookup 
(
    match_index INT UNSIGNED NOT NULL PRIMARY KEY,
    image_match TINYTEXT
);

L'eliminazione sottoquery

La query senza ordinare i risultati per la somma (TFIDF) assomiglia

SELECT match_index, SUM(tfidf) FROM ClusterMatches 
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;

Il che elimina utilizzando temporanea e utilizzando filesort

explain extended SELECT match_index, SUM(tfidf) FROM ClusterMatches 
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 14938 | Using where; Using index | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+

Sorting Problema

Tuttavia, se aggiungo ORDER BY SUM (tfdif) in

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+-------------+--------------------+
| match_index | total              |
+-------------+--------------------+
|         868 |   0.11126546561718 | 
|        4182 | 0.0238558370620012 | 
|        2162 | 0.0216601379215717 | 
|        1406 | 0.0191618576645851 | 
|        4239 | 0.0168981291353703 | 
|        1437 | 0.0160425212234259 | 
|        2599 | 0.0156466849148273 | 
|         394 | 0.0155945559963584 | 
|        3116 | 0.0151005545631051 | 
|        4028 | 0.0149106932803988 | 
+-------------+--------------------+
10 rows in set (0.03 sec)

Il risultato è opportunamente veloce a questa scala ma avente le ORDER BY SUM (TFIDF) mezzi utilizza temporanea e filesort

explain extended SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                                                     |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 65369 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+

Soluzioni possibili?

Im alla ricerca di una soluzione che non fa uso di FileSort temporanea o, lungo le linee di

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY cluster_index, match_index 
HAVING total>0.01 ORDER BY cluster_index;
dove ho bisogno di codificare una soglia per un totale, tutte le idee?

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