2015-06-03 3 views
1

Использование MySQL 5.6 У меня возникает большая проблема с производительностью при фильтрации по вычисленной формуле с использованием условий с использованием синтаксиса CASE WHEN THEN ELSE END.MySQL чрезвычайно медленная фильтрация запросов на CASE WHEN Формула

Эта формула SQL отображается Hibernate. Около 6000 строк в базе данных.
Таблица foo имеет индексы на столбцах product и barcode

1. медленных 2-16 сек

select 
    count(*) 
from 
    foo AS f 
where 
    (
     CASE WHEN f.product IS NOT NULL THEN 1 
     ELSE (
      CASE WHEN f.barcode IS NULL THEN 0 
      ELSE (
       SELECT EXISTS(
        SELECT 1 
        FROM product AS p 
        WHERE p.barcode = f.barcode 
        LIMIT 1 
       ) 
      ) END 
     ) END 
    ) = 0 

EXPLAIN Результаты:

+----+--------------------+-------+------+-------------------------------+-----+---------+-----+-------+---------------------------------------------------+ 
| id | select_type  | table | type |   possible_keys   | key | key_len | ref | rows |      Extra      | 
+----+--------------------+-------+------+-------------------------------+-----+---------+-----+-------+---------------------------------------------------+ 
| 1 | PRIMARY   | f  | ALL |        |  |   |  | 700 | Using where          | 
| 3 | DEPENDENT SUBQUERY | p  | ALL | UQ_product,IX_product_barcode |  |   |  | 3134 | Range checked for each record (index map: 0x2008) | 
+----+--------------------+-------+------+-------------------------------+-----+---------+-----+-------+---------------------------------------------------+ 

2. быстро ~ 0,4 s

select 
    * 
from 
    foo AS f 
where 
    (CASE ... END) = 0 

EXPLAIN результаты идентичны запросу подсчета.

+0

Укажите, что вы удаляете. –

ответ

2

Прежде всего, вы должны, вероятно, попытаться просмотреть выход EXPLAIN, чтобы получить дополнительную информацию.

Но в любом случае, давайте попробуем немного очистить ваш запрос и посмотреть, не можем ли мы использовать несколько индексов. Самый большой запах - CASE xxx = 0; Интересно, если парсер запросов возникают проблемы, делая эффективный план и расчета этого значения для каждой строки и сравнивая результат 0.

Так давайте перепишем это так:

where f.product is null 
and (
    f.barcode is null 
    or exists (select 1 from product p where p.barcode = f.barcode) 
) 

Если это не исправить попробуйте обновить статистику индекса с помощью ANALYZE TABLE.

+0

Использование 'EXPLAIN' в обоих запросах дает одинаковые результаты, кроме первого, очевидно, используется предложение WHERE. В моем случае я не могу переписать запрос, как вы предлагаете, поскольку я использую структуру ORM для сопоставления формулы, поэтому у меня нет доступа к предложению 'WHERE'. – djmj

+0

Хм, можете ли вы опубликовать свои объяснения? –

+0

Кажется, что это связано с столбцом 'barcode', который использует' utf8_general_ci'. Когда я удаляю сравнение штрих-кода, он работает очень быстро. – djmj

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