Ho una query per un sistema di messaggistica di contatti che sta rallentando esponenzialmente il numero maggiore di join che faccio.La query SQL diventa esponenzialmente più lenta
La struttura della tabella è fondamentalmente una tabella contatti e una tabella campi contatti.
La query unisce la tabella dei campi di contatto molte volte e per ogni join effettuato, richiede il doppio del tempo.
Questa è la query.
SELECT SQL_CALC_FOUND_ROWS
`contact_data`.`id`,
`contact_data`.`name`,
`fields0`.`value` AS `fields0`,
`fields1`.`value` AS `fields1`,
`fields2`.`value` AS `fields2`,
...etc...
CONTACT_DATA_TAGS(
GROUP_CONCAT(DISTINCT `contact_data_tags`.`name`),
GROUP_CONCAT(DISTINCT `contact_data_assignment`.`user`),
GROUP_CONCAT(DISTINCT `contact_data_read`.`user`)
) AS `tags`,
GROUP_CONCAT(DISTINCT `contact_data_assignment`.`user`) AS `assignments`,
`contact_data`.`updated`,
`contact_data`.`created`
FROM
`contact_data`
LEFT JOIN contact_data_tags ON contact_data.`id` = contact_data_tags.`data`
LEFT JOIN contact_data_assignment ON contact_data.`id` = contact_data_assignment.`data`
LEFT JOIN contact_data_read ON contact_data.`id` = contact_data_read.`data`
LEFT JOIN contact_data_fields AS fields0 ON contact_data.`id` = fields0.`contact_data_id` AND fields0.`key` = :field1
LEFT JOIN contact_data_fields AS fields1 ON contact_data.`id` = fields1.`contact_data_id` AND fields1.`key` = :field2
LEFT JOIN contact_data_fields AS fields2 ON contact_data.`id` = fields2.`contact_data_id` AND fields2.`key` = :field3
...etc...
GROUP BY contact_data.`id`
ORDER BY `id` DESC
Questa è la struttura della tabella:
CREATE TABLE IF NOT EXISTS `contact_data` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL,
`format` varchar(50) NOT NULL,
`fields` longtext NOT NULL,
`url` varchar(2000) NOT NULL,
`referer` varchar(2000) DEFAULT NULL,
`ip` varchar(40) NOT NULL,
`agent` varchar(1000) DEFAULT NULL,
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
`updater` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `url` (`url`(333)),
KEY `ip` (`ip`),
KEY `created` (`created`),
KEY `updated` (`updated`),
KEY `updater` (`updater`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `contact_data_assignment` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user` int(10) unsigned NOT NULL,
`data` int(10) unsigned NOT NULL,
`created` datetime NOT NULL,
`updater` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_assignment` (`user`,`data`),
KEY `user` (`user`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `contact_data_fields` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`contact_data_id` int(10) unsigned NOT NULL,
`key` varchar(200) NOT NULL,
`value` text NOT NULL,
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `contact_data_id` (`contact_data_id`),
KEY `key` (`key`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `contact_data_read` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user` int(10) unsigned NOT NULL,
`data` int(10) unsigned NOT NULL,
`type` enum('admin','email') NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `user` (`user`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `contact_data_tags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL,
`data` int(10) unsigned NOT NULL,
`created` datetime NOT NULL,
`updater` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_tag` (`name`,`data`),
KEY `name` (`name`),
KEY `data` (`data`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DELIMITER $$
CREATE FUNCTION `contact_data_tags`(`tags` TEXT, `assigned` BOOL, `read` BOOL) RETURNS text CHARSET latin1
BEGIN
RETURN CONCAT(
',',
IFNULL(`tags`, ''),
',',
IF(`tags` IS NULL OR FIND_IN_SET('Closed', `tags`) = 0, 'Open', ''),
',',
IF(`assigned` IS NULL, 'Unassigned', ''),
',',
IF(`read` IS NULL, 'New', ''),
','
);
END$$
DELIMITER ;
Qualcuno sa il motivo per cui funziona così lento? Cosa posso fare per renderlo più veloce? Devo modificare la query (preferirei non regolare la struttura)? C'è qualche opzione di configurazione che posso impostare per velocizzarlo?
È strano anche che sembra funzionare più velocemente sul mio computer di sviluppo Windows, rispetto al mio server di produzione di Debain (quasi istantaneo, rispetto ai 30+ secondi).
Ma la macchina Windows è molto meno potente del server Debain (8 core Xeon, 32 GB RAM).
Esecuzione di MySQL 5.1.49 su Debian (che non posso aggiornare) e 5.5.28 su Windows.
Quindi leggere che EAV non funziona bene in RDBMS (o almeno nel mio caso), è l'opzione di configurazione che potrei aumentare per farlo correre più velocemente (cioè posso solo lanciare più RAM su di esso)?
Ah, la gioia che è l'Entità-Attributo-Valore-Modello. Non funziona troppo bene nei database relazionali. http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model A RDBMS piace conoscere i suoi campi in anticipo. Hai bisogno di esporre tutti questi configurabili contact_data_fields al database (per le query)? In caso contrario, è possibile memorizzare un JSON in un CLOB. O utilizzare un database di documenti NoSQL. O se non sono configurabili, basta usare le colonne "regolari". – Thilo
@Thilo sì ho bisogno di esporli per le domande. Mi sono trasferito da JSON, per questo motivo. Correzione – Petah
: EAV funziona piuttosto bene in alcuni database, con la chiave giusta e/o la struttura della tabella di clustering. – wildplasser