简体   繁体   English

带内部连接的MySQL查询使用Order by和Group By更慢

[英]Mysql query with inner join more slow with Order by and Group By

on my vps I'm trying to execute a query, I have to extract 20 results in about 1800 records, the query is formed by 3 INNER JOIN , if I execute it without inserting the GROUP BY id ORDER BY id DESC at the end of the query query is executed in 0.0143 seconds, while if I insert the GROUP BY id ORDER BY id DESC at the end of the query, it takes 3.1447 seconds the execution, can you tell me why? 在我的vps上,我试图执行查询,我必须在大约1800条记录中提取20个结果,该查询是由3个INNER JOIN ,如果我执行该查询时未在末尾插入GROUP BY id ORDER BY id DESC查询查询将在0.0143秒内执行,而如果我在查询末尾插入GROUP BY id ORDER BY id DESC ,则需要3.1447秒的执行时间,你能告诉我为什么吗?

This is the query: 这是查询:

SELECT s.nome,s.url as urlSito,s.importospedizione,p.titolo,p.descrizione,p.prezzo,p.img,p.annata,p.formato,p.denominazione,p.regione,c.categoria,c.url,s.id AS sito,p.id AS prodotto,pp.prezzo AS old,pp.data,p.sku 
FROM prodotti AS p 
INNER JOIN siti AS s ON p.sito = s.id 
INNER JOIN categorie AS c ON p.categoria = c.id 
INNER JOIN prodotti_prezzi AS pp ON p.id = pp.prodotto 
WHERE p.attivo = 1 AND s.attivo = 1 AND p.forced = 0  AND 
    ( p.regione = 'Valle d\'Aosta' OR p.regione = 'Piemonte' OR p.regione = 'Liguria' OR 'Lombardia' OR p.regione = 'Trentino-Alto Adige' OR p.regione = 'Veneto' OR p.regione = 'Friuli-Venezia Giulia' OR p.regione = 'Emilia-Romagna' OR p.regione = 'Toscana' OR p.regione = 'Umbria' OR p.regione = 'Lazio' OR p.regione = 'Marche' OR p.regione = 'Abruzzo' OR p.regione = 'Molise' OR p.regione = 'Campania' OR p.regione = 'Puglia' OR p.regione = 'Basilicata' OR p.regione = 'Calabria' OR p.regione = 'Sardegna' OR p.regione = 'Sicilia' )
GROUP BY p.id  
ORDER BY p.prezzo ASC  
LIMIT 0,20

在此处输入图片说明

This is the structure: 结构如下:

Table prodotti: 表prodotti:

CREATE TABLE `prodotti` (   `id` int(11) NOT NULL,   `sku` text NOT NULL,   `titolo` text NOT NULL,   `descrizione` longtext NOT NULL,   `sito` int(11) NOT NULL,   `prezzo` double NOT NULL,   `qta` int(11) NOT NULL,   `url` text NOT NULL,   `produttore` text NOT NULL,   `regione` text NOT NULL,   `denominazione` text NOT NULL,   `annata` int(11) NOT NULL,   `formato` text NOT NULL,   `attivo` int(11) NOT NULL,   `img` text NOT NULL,   `home` int(11) NOT NULL,   `categoria` int(11) NOT NULL,   `consigli` int(11) NOT NULL,   `forced` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `prodotti`
-- ALTER TABLE `prodotti`   ADD PRIMARY KEY (`id`),   ADD UNIQUE KEY `id` (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `prodotti`
-- ALTER TABLE `prodotti`   MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

Table siti: 表siti:

CREATE TABLE `siti` (
  `id` int(11) NOT NULL,
  `nome` text NOT NULL,
  `indirizzo` text NOT NULL,
  `tel` text NOT NULL,
  `pagamento` text NOT NULL,
  `spedizione` text NOT NULL,
  `url` text NOT NULL,
  `email` text NOT NULL,
  `password` varchar(40) NOT NULL,
  `emailweb` text NOT NULL,
  `zone` text NOT NULL,
  `data` int(11) NOT NULL,
  `aggiornamento` int(11) NOT NULL,
  `urlaggiornamento` text NOT NULL,
  `img` text NOT NULL,
  `click` double NOT NULL,
  `max` double NOT NULL,
  `ultimo` int(11) NOT NULL,
  `attivo` int(11) NOT NULL,
  `importospedizione` double NOT NULL,
  `descrizione` longtext NOT NULL,
  `web` text NOT NULL,
  `iva` text NOT NULL,
  `sociale` text NOT NULL,
  `avviso` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `siti`
--
ALTER TABLE `siti`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `siti`
--
ALTER TABLE `siti`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

Table prodotti_prezzi: 表prodotti_prezzi:

CREATE TABLE `prodotti_prezzi` (
  `id` int(11) NOT NULL,
  `prodotto` int(11) NOT NULL,
  `prezzo` double NOT NULL,
  `data` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `prodotti_prezzi`
--
ALTER TABLE `prodotti_prezzi`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `prodotti_prezzi`
--
ALTER TABLE `prodotti_prezzi`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

Table categorie: 表类别:

CREATE TABLE `categorie` (
  `id` int(11) NOT NULL,
  `categoria` text NOT NULL,
  `url` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `categorie`
--
ALTER TABLE `categorie`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `categorie`
--
ALTER TABLE `categorie`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

I tried to run the same query, on a database clone (same data) on two other servers is the problem does not occur, it only happens when I run it from my vps. 我尝试在其他两台服务器上的数据库克隆(相同数据)上运行相同的查询,是不会发生问题,仅当我从vps运行它时才会发生。

Here is my configuration: 这是我的配置:

Database server 数据库服务器

  • Server: Localhost via UNIX socket 服务器:通过UNIX套接字的Localhost
  • Server type: MySQL 服务器类型:MySQL
  • Server version: 5.7.22-0ubuntu0.16.04.1 - (Ubuntu) 服务器版本:5.7.22-0ubuntu0.16.04.1-(Ubuntu)
  • Protocol version: 10 协议版本:10
  • User: root@localhost 用户:root @ localhost
  • Server charset: UTF-8 Unicode (utf8) 服务器字符集:UTF-8 Unicode(utf8)

Web server 网络服务器

  • Apache/2.4.18 (Ubuntu) mod_fcgid/2.3.9 OpenSSL/1.0.2g Apache / 2.4.18(Ubuntu)mod_fcgid / 2.3.9 OpenSSL / 1.0.2g
  • Database client version: libmysql - mysqlnd 5.0.12-dev - 20150407 - $Id: 38fea24f2847fa7519001be390c98ae0acafe387 $ 数据库客户端版本:libmysql-mysqlnd 5.0.12-dev-20150407-$ Id:38fea24f2847fa7519001be390c98ae0acafe387 $
  • PHP extension: mysqliDocumentation curlDocumentation mbstringDocumentation PHP扩展名:mysqliDocumentation curlDocumentation mbstringDocumentation
  • PHP version: 7.2.5-1+ubuntu16.04.1+deb.sury.org+1 PHP版本:7.2.5-1-1 + ubuntu16.04.1 + deb.sury.org + 1

phpMyAdmin: Version information: 4.6.6deb1+deb.cihar.com~xenial.2 phpMyAdmin:版本信息:4.6.6deb1 + deb.cihar.com〜xenial.2

Thanks a lot to everyone. 非常感谢大家。

EDIT 编辑

EXPLAIN result: 说明结果:

在此处输入图片说明

EDIT 2: 编辑2:

EXPLAIN result on second database: 在第二个数据库上解释结果:

在此处输入图片说明

For your query, 对于您的查询,

SELECT s.nome,s.url as urlSito,s.importospedizione,p.titolo,p.descrizione,p.prezzo,p.img,p.annata,p.formato,p.denominazione,p.regione,c.categoria,c.url,s.id AS sito,p.id AS prodotto,pp.prezzo AS old,pp.data,p.sku 
FROM prodotti AS p 
INNER JOIN siti AS s ON p.sito = s.id 
INNER JOIN categorie AS c ON p.categoria = c.id 
INNER JOIN prodotti_prezzi AS pp ON p.id = pp.prodotto 
WHERE p.attivo = 1 AND s.attivo = 1 AND p.forced = 0  AND 
    ( p.regione = 'Valle d\'Aosta' OR p.regione = 'Piemonte' OR p.regione = 'Liguria' OR 'Lombardia' OR p.regione = 'Trentino-Alto Adige' OR p.regione = 'Veneto' OR p.regione = 'Friuli-Venezia Giulia' OR p.regione = 'Emilia-Romagna' OR p.regione = 'Toscana' OR p.regione = 'Umbria' OR p.regione = 'Lazio' OR p.regione = 'Marche' OR p.regione = 'Abruzzo' OR p.regione = 'Molise' OR p.regione = 'Campania' OR p.regione = 'Puglia' OR p.regione = 'Basilicata' OR p.regione = 'Calabria' OR p.regione = 'Sardegna' OR p.regione = 'Sicilia' )
GROUP BY p.id  
ORDER BY p.prezzo ASC  
LIMIT 0,20

you need to have indexes on the fields used to join the tables. 您需要在用于联接表的字段上具有索引。 You have indexes on the primary keys, but nothing to match them with, so the database has to search through every record of the joined tables. 您在主键上有索引,但是没有与之匹配的索引,因此数据库必须搜索联接表的每个记录。

Add indexes to prodotti.sito , prodotti.categoria , prodotti_prezzi.prodotto and that should make a world of difference. 将索引添加到prodotti.sitoprodotti.categoriaprodotti_prezzi.prodotto ,这应该会有所作为。 You could also throw in indexes on attivo , forced , and regione for good measure. 您也可以在attivoforcedregioneattivo索引,以提高性能。

My suspicion is that your indexes are not the same on all 3 servers, and the slow one is lacking the indexes. 我怀疑您的索引在所有3台服务器上都不相同,而慢速的索引却缺少索引。


FWIW, a couple of other notes: FWIW,其他一些注意事项:

  1. On prodotti, unique key id is superfluous; 在prodotti上, unique key id是多余的; primary key is by definition unique 根据定义, primary key是唯一的

  2. p.regione = 'Valle d\\'Aosta' OR p.regione = 'Piemonte' OR p.regione = 'Liguria' OR 'Lombardia' OR p.regione = 'Trentino-Alto Adige' OR p.regione = 'Veneto' OR p.regione = 'Friuli-Venezia Giulia' OR p.regione = 'Emilia-Romagna' OR p.regione = 'Toscana' OR p.regione = 'Umbria' OR p.regione = 'Lazio' OR p.regione = 'Marche' OR p.regione = 'Abruzzo' OR p.regione = 'Molise' OR p.regione = 'Campania' OR p.regione = 'Puglia' OR p.regione = 'Basilicata' OR p.regione = 'Calabria' OR p.regione = 'Sardegna' OR p.regione = 'Sicilia' )

    can be more easily expressed as 可以更容易地表示为

    p.regione IN('Valle d\\'Aosta','Piemonte','Liguria','Lombardia','Trentino-Alto Adige','Veneto','Friuli-Venezia Giulia','Emilia-Romagna','Toscana','Umbria','Lazio','Marche','Abruzzo','Molise','Campania','Puglia','Basilicata','Calabria','Sardegna','Sicilia')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM