Как оптимизировать медленный «выборочный» запрос для трех таблиц по 40 тыс. Строк, который возвращает только 22 результата - PullRequest
14 голосов
/ 27 мая 2011

Итак, этот запрос написан кем-то другим, и я пытаюсь провести рефакторинг, который извлекает некоторые элементы / материалы для предмета (как правило, обуви).

Существует множество продуктов и, следовательно, множество объединяющих записи в таблицах, но для них доступно лишь несколько функций.Я думаю, что должен быть способ сократить необходимость касаться «большого» списка элементов, чтобы получить эти функции, и я слышал, что следует избегать отдельного, но у меня нетоператор, который может заменить «различные» параметры здесь.

Согласно моим журналам, я получаю медленные времена результата:

Query_time: 7 Lock_time: 0 Rows_sent: 32 Rows_examined:5362862

Query_time: 8 Lock_time: 0 Rows_sent: 22 Rows_examined: 6581994

Как говорится в сообщении, иногда это занимает 7 или 8 секунд, а иногда или каждый раз, когда оно запрашивает5 миллионов строк.

Это может быть связано с другой загрузкой, возникающей в то же время, потому что здесь выборки выполняются в базе данных непосредственно из командной строки mysql:

mysql> SELECT DISTINCT features.FeatureId, features.Name
       FROM features, itemsfeatures, items
       WHERE items.FlagStatus != 'U'
         AND items.TypeId = '13'
         AND features.Type = 'Material'
         AND features.FeatureId = itemsfeatures.FeatureId
       ORDER BY features.Name;
+-----------+--------------------+
| FeatureId | Name               |
+-----------+--------------------+
|        40 | Alligator          |
|        41 | Burnished Calfskin |
|        42 | Calfskin           |
|        59 | Canvas             |
|        43 | Chromexcel         |
|        44 | Cordovan           |
|        57 | Cotton             |
|        45 | Crocodile          |
|        58 | Deerskin           |
|        61 | Eel                |
|        46 | Italian Leather    |
|        47 | Lizard             |
|        48 | Nappa              |
|        49 | NuBuck             |
|        50 | Ostrich            |
|        51 | Patent Leather     |
|        60 | Rubber             |
|        52 | Sharkskin          |
|        53 | Silk               |
|        54 | Suede              |
|        56 | Veal               |
|        55 | Woven              |
+-----------+--------------------+
22 rows in set (0.00 sec)

mysql> select count(*) from features;
+----------+
| count(*) |
+----------+
|      122 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from itemsfeatures;
+----------+
| count(*) |
+----------+
|    38569 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from items;
+----------+
| count(*) |
+----------+
|     8656 |
+----------+
1 row in set (0.00 sec)

explain SELECT DISTINCT features.FeatureId, features.Name  FROM features, itemsfeatures, items    WHERE items.FlagStatus != 'U'  AND items.TypeId = '13'  AND features.Type = 'Material' AND features.FeatureId = itemsfeatures.FeatureId  ORDER BY features.Name;
+----+-------------+---------------+------+-------------------+-----------+---------+---------------------------------+------+----------------------------------------------+
| id | select_type | table         | type | possible_keys     | key       | key_len | ref                             | rows | Extra                                        |
+----+-------------+---------------+------+-------------------+-----------+---------+---------------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | features      | ref  | PRIMARY,Type      | Type      | 33      | const                           |   21 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | itemsfeatures | ref  | FeatureId         | FeatureId | 4       | sherman_live.features.FeatureId |  324 | Using index; Distinct                        |
|  1 | SIMPLE      | items         | ALL  | TypeId,FlagStatus | NULL      | NULL    | NULL                            | 8656 | Using where; Distinct; Using join buffer     |
+----+-------------+---------------+------+-------------------+-----------+---------+---------------------------------+------+----------------------------------------------+
3 rows in set (0.04 sec)

Редактировать:

Вот примерные результаты без отличных (но с ограничением, поскольку в противном случае он просто зависает) для сравнения:

SELECT features.FeatureId, features.Name        FROM features, itemsfeatures, items        WHERE items.FlagStatus != 'U'          AND items.TypeId = '13'          AND features.Type = 'Material'          AND features.FeatureId = itemsfeatures.FeatureId        ORDER BY features.Name limit 10;
+-----------+-----------+
| FeatureId | Name      |
+-----------+-----------+
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
|        40 | Alligator |
+-----------+-----------+
10 rows in set (23.30 sec)

здесь используется группа вместо выделенного отличного:

SELECT features.FeatureId, features.Name        FROM features, itemsfeatures, items        WHERE items.FlagStatus != 'U'          AND items.TypeId = '13'          AND features.Type = 'Material'          AND features.FeatureId = itemsfeatures.FeatureId        group by features.name ORDER BY features.Name;
+-----------+--------------------+
| FeatureId | Name               |
+-----------+--------------------+
|        40 | Alligator          |
|        41 | Burnished Calfskin |
|        42 | Calfskin           |
|        59 | Canvas             |
|        43 | Chromexcel         |
|        44 | Cordovan           |
|        57 | Cotton             |
|        45 | Crocodile          |
|        58 | Deerskin           |
|        61 | Eel                |
|        46 | Italian Leather    |
|        47 | Lizard             |
|        48 | Nappa              |
|        49 | NuBuck             |
|        50 | Ostrich            |
|        51 | Patent Leather     |
|        60 | Rubber             |
|        52 | Sharkskin          |
|        53 | Silk               |
|        54 | Suede              |
|        56 | Veal               |
|        55 | Woven              |
+-----------+--------------------+
22 rows in set (13.28 sec)

Редактировать: Добавлена ​​награда

... Поскольку я пытаюсь понять эту общую проблему, как заменить неправильные отдельные запросы в целом, в дополнение к медлительности, к которой стремится этот запроск делу.

Мне интересно, является ли замена для выбранного отдельного лица, как правило, группой (хотя в данном случае это не всеобъемлющее решение, поскольку оно все еще медленное)?

Ответы [ 3 ]

9 голосов
/ 27 мая 2011

Похоже, вам не хватает условия JOIN, связывающего itemsfeatures с items. Это более очевидно, если вы напишите запрос, используя явные операции JOIN.

SELECT DISTINCT f.FeatureId, f.Name  
    FROM features f
        INNER JOIN itemsfeatures ifx
            ON f.FeatureID = ifx.FeatureID
        INNER JOIN items i
            ON ifx.ItemID = i.ItemID /* This is the part you're missing */
    WHERE i.FlagStatus != 'U'  
        AND i.TypeId = '13'  
        AND f.Type = 'Material' 
    ORDER BY f.Name;
6 голосов
/ 18 июля 2011

Как утверждает Джо, похоже, что отсутствует условие соединения

Это ваш текущий запрос

SELECT DISTINCT 
        features.FeatureId, 
        features.Name
FROM    features, 
        itemsfeatures, 
        items
WHERE   items.FlagStatus != 'U'
        AND items.TypeId = '13'
        AND features.Type = 'Material'
        AND features.FeatureId = itemsfeatures.FeatureId
ORDER BY features.Name

Это ваш запрос с явными объединениями

SELECT DISTINCT 
        features.FeatureId, 
        features.Name
FROM    features INNER JOIN
        itemsfeatures on features.FeatureId = itemsfeatures.FeatureId CROSS JOIN
        items
WHERE   items.FlagStatus != 'U'
        AND items.TypeId = '13'
        AND features.Type = 'Material'
ORDER BY features.Name

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

SELECT DISTINCT 
        features.FeatureId, 
        features.Name
FROM    features, 
        itemsfeatures
WHERE   features.Type = 'Material'
        AND features.FeatureId = itemsfeatures.FeatureId
ORDER BY features.Name

То, как запрос написан, похоже, он хочет получить списокматериалов для элементов с typeID 13 и Flagstatus <> U. В этом случае результат, возвращаемый запросом orignial, неверен.Он просто возвращает все материалы для всех элементов.

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

SELECT  features.FeatureId, 
        features.Name
FROM    features INNER JOIN
        itemsfeatures on features.FeatureId = itemsfeatures.FeatureId INNER JOIN
        items on itemsfeatures.ItemID = items.ItemID
WHERE   items.FlagStatus != 'U'
        AND items.TypeId = '13'
        AND features.Type = 'Material'
GROUP BY features.FeatureId, 
        features.Name
ORDER BY features.Name

С этим, теперь отсортированным, теперь прибывает скорость.Создайте следующие три индекса.

FeaturesIndex(Type,FeatureID,Name)
ItemsFeaturesIndex(FeatureId)
ItemsIndex(TypeId,FlagStatus,ItemID)

Это должно ускорить как ваш текущий запрос, так и тот, который я перечислил.

3 голосов
/ 14 июля 2011

Я почти уверен, что ответ Джо верен. Но если вы считаете, что Джо не прав и хотите получить те же результаты, что и исходный запрос, но быстрее, используйте этот запрос:

SELECT DISTINCT features.FeatureId, features.Name
    FROM features, itemsfeatures
    WHERE features.Type = 'Material'
        AND features.FeatureId = itemsfeatures.FeatureId
    ORDER BY features.Name;
...