Оптимизировать My SQL Index для нескольких таблиц

0

У меня 5 таблиц в mysql. И когда я хочу выполнить запрос, он выполняется слишком долго. Есть структура моих таблиц:

  1. Reciept (count rows: 23799640) Структура таблицы reciept
  2. reciept_goods (count rows: 39398989) Структура таблицы reciept_goods
  3. good (count rows: 17514) хорошая структура таблицы
  4. good_categories (count rows: 121) Структура таблицы good_categories
  5. retail_category (count rows: 10) Структура таблицы retail_category

Мои показатели:

  1. Дата → reciept.date # 1
  2. reciept_goods_index → reciept_goods.recieptId # 1, reciept_goods.shopId # 2, reciept_goods.goodId # 3
  3. category_id → good.category_id # 1

У меня есть следующий запрос sql:

SELECT 
      R.shopId, 
      sales, 
      sum(Amount) as sum_amount,       
      count(distinct R.id) as count_reciept, 
      RC.id,  
      RC.name
   FROM
      reciept R
         JOIN reciept_goods RG
            ON R.id = RG.RecieptId 
            AND R.ShopID = RG.ShopId
            JOIN good G
               ON RG.GoodId = G.id
               JOIN good_categories GC 
                  ON G.category_id = GC.id
                  JOIN retail_category RC
                     ON GC.retail_category_id = RC.id                                        
   WHERE 
      R.date >= '2018-01-01 10:00:00'                               
   GROUP BY 
      R.shopId, 
      R.sales, 
      RC.id

Объяснение этого запроса дает следующий результат: Объяснить запрос и время выполнения = 236 сек.

если использовать straight_join good ON (good.id = reciept_goods.GoodId ) объяснить запрос Объяснить запрос и время выполнения = 31 с

SELECT STRAIGHT_JOIN ... rest of query

Я думаю, эта проблема в индексах моих таблиц, но я не понимаю, как их исправить, может кто-нибудь мне помочь?

  • 0
    Какой процент ваших строк в reciept имеет date>='2018-01-01 10:00:00' ? Есть ли значительное количество рецептов, которые имеют 0 строк в reciept_goods ? Кроме того: 31s подходит для вас, и вы просто хотите знать, зачем вам нужно прямое соединение или какое время выполнения вам нужно? (Я знаю, это никогда не может быть достаточно быстрым ...)
  • 0
    у каждого квитанции есть минимум 1 reciept_goods (на avarage 2), в таблице квитанций у меня максимальная дата '2018-01-15 20:55:29' и количество reciept.date> = '2018-01-01 10:00:00' AND reciept.date <= '2018-01-15 20:55:29' = 349876. Я тестирую его на тестовом сервере, поэтому думаю, что на реальном сервере с большими ресурсами это будет работать около 12 секунд,
Показать ещё 3 комментария
Теги:
database
join
indexing

2 ответа

0
Лучший ответ

Примерно 2% ваших строк в reciepts имеющих правильную дату, выбранный второй план выполнения (с помощью straight_join) представляется правильным порядком выполнения. Вы можете оптимизировать его, добавив следующие индексы покрытия:

 reciept(date, sales)
 reciept_goods(recieptId, shopId, goodId, amount)

Я предполагаю, что порядок столбцов в вашем основном ключе для reciept_goods настоящее время (goodId, recieptId, shopId) (или (goodId, shopId, receiptId)). Вы можете изменить это, чтобы recieptId, shopId, goodId (и если вы посмотрите, например, на имя таблицы, вы, возможно, захотите сделать это в любом случае); в этом случае вам не нужен второй индекс (по крайней мере для этого запроса). Я бы предположил, что этот первичный ключ заставил MySQL принять более медленный план выполнения (конечно, предполагая, что он будет быстрее), хотя иногда это просто плохая статистика, особенно на тестовом сервере.

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

  • 0
    Я изменяю первичный ключ для <code> reciept_goods </ code> на <code> recieptId, shopId, goodId </ code>. И это помогло, но только когда мы используем <code> количество дней <= 29 </ code>. Например: <code> WHERE R.date> = '2017-12-01 00:00:00' AND R.date <= '2017-12-29 23:59:59' ... остаток запроса </ код>. Если мы используем интервал: WHERE R.date> = '2017-12-01 00:00:00' AND R.date <= '2017-12-30 23:59:59' ... остаток запроса или больший интервал , Объяснение этого запроса дает результат, равный времени выполнения = 236сек
  • 0
    MySQL иногда просто ошибается, хотя я на самом деле не вижу причин, по которым MySQL все еще может пойти по этому пути. Возможно, вы используете MyISAM вместо InnoDB? Вы show create table reciept_goods , что действительно изменили первичный ключ (с помощью show create table reciept_goods он также сообщает вам, используете ли вы MyISAM)? Не могли бы вы добавить планы выполнения для коротких и длинных диапазонов дат? Я предполагаю , что использование straight_join держит ваш запрос быстро, так что у вас есть обходной путь для вашей насущной проблемы? Несвязанный, но любопытный: изменение ПК улучшило скорость выполнения? Вы добавили первый индекс?
0

Похоже, вы зависите от того, как пройти через пару из многих: много таблиц? Многие люди проектируют их неэффективно.

Здесь я составил список из 7 советов по созданию более эффективных таблиц сопоставления. Наиболее важным является использование составных индексов.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню