Mysql-запрос с внутренним объединением медленнее с Order by и Group By - PullRequest
0 голосов
/ 18 мая 2018

на моем VPS Я пытаюсь выполнить запрос, я должен извлечь 20 результатов в 1800 записей, запрос формируется из 3 INNER JOIN, если я выполняю его без вставки GROUP BY id ORDER BY id DESC в конце запрос выполняется за 0,0143 секунды, а если я вставлю GROUP BY id ORDER BY id DESC в конце запроса, это займет 3,1447 секунды, можете ли вы сказать мне, почему?

Это запрос:

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

enter image description here

Это структура:

Таблица продотти:

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;

Таблица сити:

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;

Таблица 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;

Таблица категорий:

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;

Я пытался выполнить тот же запрос на клоне базы данных (те же данные) на двух других серверах, проблема не возникает, это происходит только когда я запускаю его с моего VPS.

Вот моя конфигурация:

Сервер базы данных

  • Сервер: локальный хост через сокет UNIX
  • Тип сервера: MySQL
  • Версия сервера: 5.7.22-0ubuntu0.16.04.1 - (Ubuntu)
  • Версия протокола: 10
  • Пользователь: root @ localhost
  • Серверная кодировка: UTF-8 Unicode (utf8)

Веб-сервер

  • Apache / 2.4.18 (Ubuntu) mod_fcgid / 2.3.9 OpenSSL / 1.0.2g
  • Версия клиента базы данных: libmysql - mysqlnd 5.0.12-dev - 20150407 - $ Id: 38fea24f2847fa7519001be390c98ae0acafe387 $
  • Расширение PHP: mysqliDocumentation curlDocumentation mbstringDocumentation
  • Версия PHP: 7.2.5-1 + ubuntu16.04.1 + deb.sury.org + 1

phpMyAdmin: Информация о версии: 4.6.6deb1 + deb.cihar.com ~ xenial.2

Большое спасибо всем.

EDIT

ОБЪЯСНИТЬ результат:

enter image description here

РЕДАКТИРОВАТЬ 2:

ОБЪЯСНИТЬ результат по второй базе данных:

enter image description here

1 Ответ

0 голосов
/ 18 мая 2018

Для вашего запроса,

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

вам нужно иметь индексы для полей, используемых для объединения таблиц.У вас есть индексы для первичных ключей, но нет ничего, с чем их можно было бы сопоставить, поэтому базе данных приходится искать в каждой записи соединенных таблиц.

Добавить индексы к prodotti.sito, prodotti.categoria, prodotti_prezzi.prodotto иэто должно иметь огромное значение.Вы также можете добавить индексы для attivo, forced и regione для правильной оценки.

Я подозреваю, что ваши индексы не одинаковы на всех 3 серверах, а медленный отсутствуетиндексы.


FWIW, пара других примечаний:

  1. На prodotti, unique key id является излишним;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' )

    может быть более легко выражено как

    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')

...