2013-08-06 2 views
1

Я столкнулся с проблемой производительности с этим запросом. Я долго смотрел на эту проблему, царапая голову. В какой-то момент этот запрос был довольно быстрым, но как только данные росли, он становился все медленнее и медленнее. Таблица «Сообщений» имеет +5 миллионов строк, таблица «Items» имеет +6000 строк. Эти таблицы постоянно растут ежедневно.MAX (ID) с функцией сравнения функции IN()

SELECT Posts.itemID, Items.itemName, Items.itemImage, Items.guid, Posts.price, 
Posts.quantity, Posts.date, Games.name, Items.profit FROM Items 
INNER JOIN Posts ON Items.itemID=Posts.itemID 
INNER JOIN Games ON Posts.gameID=Games.gameID 
WHERE Posts.postID IN (SELECT MAX(postID) FROM Posts GROUP BY itemID) AND Posts.gameID=:gameID 
    AND Posts.price BETWEEN :price_min AND :price_max 
    AND Posts.quantity BETWEEN :quant_min AND :quant_max 
    AND Items.profit BETWEEN :profit_min AND :profit_max 
ORDER BY Items.profit DESC LIMIT 0, 20 

В коде я разделил запрос и дополнительный запрос на два. Вместе они работали медленнее. Все это было хорошо и хорошо, пока данные в сообщениях и статьях не начали расти. Операторы 'where', которые я вставлял **, получают конкатенацию в зависимости от того, какие фильтры установлены.

Вот EXPLAIN, который я получаю. (Это запрос, без вспомогательного запроса) https://docs.google.com/file/d/0B1jxMdMfC35VeDBEbnJISmNGb3c/edit?usp=sharing

SHOW INDEX FROM Сообщений:

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Posts |   0 | PRIMARY |   1 | postID  | A   |  5890249 |  NULL | NULL |  | BTREE  |   |    | 
| Posts |   1 | itemID |   1 | itemID  | A   |  16453 |  NULL | NULL | YES | BTREE  |   |    | 
| Posts |   1 | gameID |   1 | gameID  | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

SHOW INDEX FROM Items;

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Items |   0 | PRIMARY |   1 | itemID  | A   |  6452 |  NULL | NULL |  | BTREE  |   |    | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

ПОКАЖИТЕ ИНДЕКС ИЗ Игры;

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Games |   0 | PRIMARY |   1 | gameID  | A   |  2487 |  NULL | NULL |  | BTREE  |   |    | 
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

Есть в любом случае я могу сделать этот запрос быстрее? У вас есть какие-то советы? Есть ли лучший способ написать этот запрос? Вся помощь приветствуется.

EXPLAIN Предлагаемый запрос:

+----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+ 
    | id | select_type | table  | type | possible_keys   | key  | key_len | ref      | rows | Extra          | 
    +----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+ 
    | 1 | PRIMARY  | <derived2> | ALL | NULL     | NULL | NULL | NULL      |  19 | Using temporary; Using filesort    | 
    | 1 | PRIMARY  | p   | eq_ref | PRIMARY,itemID,gameID | PRIMARY | 4  | q.postID     |  1 |            | 
    | 1 | PRIMARY  | i   | eq_ref | PRIMARY    | PRIMARY | 2  | db323245342342345.p.itemID |  1 | Using where         | 
    | 1 | PRIMARY  | g   | eq_ref | PRIMARY    | PRIMARY | 4  | db323245342342345.p.gameID |  1 | Using where         | 
    | 2 | DERIVED  | p   | ref | itemID,gameID   | gameID | 2  |       | 2945124 | Using where; Using temporary; Using filesort | 
    | 2 | DERIVED  | i   | eq_ref | PRIMARY    | PRIMARY | 2  | db323245342342345.p.itemID |  1 | Using where         | 
    +----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+ 
+0

Может быть, ваша статистика устарела. Используйте команду ANALYZE TABLE, чтобы обновить их для каждой таблицы в запросе. –

+0

Думал, что это тоже было, но он говорит, что это «ОК» – roadrunner

+0

'(SELECT MAX (postID) FROM Posts GROUP BY itemID)': 'GROUP BY' выглядит бесполезным для меня. – wildplasser

ответ

0

Не уверен, если это поможет, но попробуйте переместить подзапрос до конца вашей ИНЕКЕ, а также попробовать сделать это коррелированных подзапросов. Переместите фильтр по элементам вверх.

SELECT 
p1.itemID, 
Items.itemName, 
Items.itemImage, 
Items.guid, 
p1.price, 
p1.quantity, 
p1.date, 
Games.name, 
Items.profit 
FROM Items 
INNER JOIN Posts p1 ON Items.itemID=p1.itemID 
INNER JOIN Games ON p1.gameID=Games.gameID 
WHERE Items.profit BETWEEN :profit_min AND :profit_max 
    AND p1.gameID=:gameID 
    AND p1.price BETWEEN :price_min AND :price_max 
    AND p1.quantity BETWEEN :quant_min AND :quant_max 
    AND p1.postID IN (SELECT MAX(p2.postID) FROM posts p2 WHERE p2.itemID = p1.ItemID GROUP BY p2.itemID) 
ORDER BY 
Items.profit DESC 
LIMIT 0, 20 
  • Кроме того, убедитесь, что вы создаете индекс на столбы (Itemid, GameID,) сообщения дана
+0

Привет @ sl0ppy! Я пробовал ваш запрос, но это также занимает довольно много времени. Я предполагаю, что max() в таблице из 4+ миллионов строк занимает немного времени. Возможно, я смогу найти другое решение, реструктурируя базу данных. – roadrunner

+0

@roadrunner: У вас есть индекс, который я предложил? Обратите внимание, что это совокупный индекс, а не отдельные индексы для каждого столбца. Кроме того, да, это будет медленным, если вы не найдете способ отфильтровать этот подзапрос Max() немного больше. Обычно я предлагаю вам создать этот индекс с помощью PostID DESC, но MySQL не поддерживает порядок DESC. –

+0

Извините за медленные ответы. Спасибо, что так терпеливы. Использование составного индекса было действительно намного быстрее. Однако я решил пойти на другой подход. Решил денормализовать одну из таблиц. – roadrunner

2

попытаться переписать его с JOIN. Что-то вроде

SELECT p.itemID, 
     i.itemName, 
     i.itemImage, 
     i.guid, 
     p.price, 
     p.quantity, 
     p.date, 
     g.name, 
     i.profit 
    FROM 
(
    SELECT MAX(postID) postID 
     FROM Posts p JOIN Items i 
     ON p.itemID = i.itemID 
    WHERE p.gameID = :gameID 
     AND p.price BETWEEN :price_min AND :price_max 
     AND p.quantity BETWEEN :quant_min AND :quant_max 
     AND i.profit BETWEEN :profit_min AND :profit_max 
    GROUP BY itemID 
) q JOIN Posts p 
    ON q.postID = p.postID JOIN Items i 
    ON p.itemID = i.itemID JOIN Games g 
    ON p.gameID = g.gameID 
ORDER BY i.profit DESC 
LIMIT 0, 20 
+0

@roadrunner Помогло ли это? – peterm

+0

Hi peterm. Я просто тестировал запрос. Кажется, это похоже на другое. Для выполнения требуется около 5-6 секунд. Может ли это быть чем-то еще, что замедляет эти запросы? – roadrunner

+0

@roadrunner Привет. У вас есть все необходимые индексы (по столбцам, которые вы присоединяете, и вы фильтруете в разделе 'WHERE')? Можете ли вы разместить полный запрос EXPLAIN на предлагаемом запросе и «ПОКАЖИТЕ УКАЗАТЕЛЬ ОТ сообщений; SHOW INDEX FROM Items; ** в текстовом формате **? – peterm

Смежные вопросы