1) Приведенный ниже запрос выполняется минимум для 1 миллиона записей. Прямо сейчас это дает результаты в 70ms to 1s. Хорошая производительность. Какое идеальное время, когда запрос должен возвращать результаты. (Система MySql InnoDB) все столбцы находятся в одной таблице

SELECT 
    *
FROM
    rgb
WHERE
    ((tcount = 16 AND r1 = 3 AND r2 = 5
        AND r3 = 8)
        OR (r1 = 8 AND r2 = 5)
        OR (r1 = 5 AND r2 = 8)
        OR (r1 = 3 AND r2 = 8)
        OR (r1 = 5 AND r2 = 3)
        OR (r1 = 3 AND r2 = 5)
        OR (r1 = 8 AND r2 = 3))
order by case
    when
        (tcount = 16 AND r1 = 3 AND r2 = 5
            AND r3 = 8)
    then
        1
    else 2
end

2) Могу ли я включить в предложение WHERE длинное условие? Все данные должны быть отсканированы из одной таблицы.

1
Lajpat 24 Фев 2014 в 15:34
Для R1, R2 и R3, являются ли значения 3, 5 и 8 единственно возможными значениями? Или только те, которые вам интересны.
 – 
DRapp
24 Фев 2014 в 15:54
Сколько строк возвращает этот запрос (приблизительно)?
 – 
krokodilko
24 Фев 2014 в 16:05

4 ответа

Лучший ответ

Я бы попытался иметь индекс покрытия для вашего запроса (r1, r2, r3, tcount)

И предложение WHERE вроде

where
       r1 in ( 3, 5, 8 )
   AND r2 in ( 3, 5, 8 )
   AND r1 != r2
   OR ( r1 = 3 and r2 = 5 and r3 = 8 and tcount = 16 )
0
DRapp 24 Фев 2014 в 15:59
@CuriousLajpat, только для ухмылки, да, это сработало, но как это помогло в производительности, хотя оно значительно сократило читаемость критериев where.
 – 
DRapp
24 Фев 2014 в 18:04

Почему бы не использовать этот попроще? вместо использования набора OR s

  SELECT 
*
FROM
rgb
WHERE
((tcount = 16 AND r1 = 3 AND r2 = 5
    AND r3 = 8)
    OR (r1, r2) IN ((8,5),(5, 8), (3, 8),(5,3),(3,5),(8,3))

order by case
when
    (tcount = 16 AND r1 = 3 AND r2 = 5
        AND r3 = 8)
then
    1
else 2
end
3
echo_Me 24 Фев 2014 в 16:09
3
+1 за (r1, r2) IN ( ...) - я не знал, что это возможно :)
 – 
SebastianH
24 Фев 2014 в 15:59
Спасибо :). Да, можно проверить эту демонстрацию
 – 
echo_Me
24 Фев 2014 в 16:01

Оптимизация SQL частично зависит от распределения ваших данных. Мы не можем его угадать, поэтому мы не можем ответить, каково стандартное время для вашего запроса. Но MySQL может сделать это за вас. Используйте EXPLAIN:

EXPLAIN SELECT 
    *
FROM
    rgb
WHERE
    ((tcount = 16 AND r1 = 3 AND r2 = 5
        AND r3 = 8)
        OR (r1 = 8 AND r2 = 5)
        OR (r1 = 5 AND r2 = 8)
        OR (r1 = 3 AND r2 = 8)
        OR (r1 = 5 AND r2 = 3)
        OR (r1 = 3 AND r2 = 5)
        OR (r1 = 8 AND r2 = 3))
order by case
    when
        (tcount = 16 AND r1 = 3 AND r2 = 5
            AND r3 = 8)
    then
        1
    else 2
end

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

1
Raul Andres 24 Фев 2014 в 15:50

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

(SELECT r.*
 FROM rgb r
 WHERE (tcount = 16 AND r1 = 3 AND r2 = 5 AND r3 = 8)
) UNION ALL
(SELECT r.*
 FROM rgb r
 WHERE (r1 = 8 AND r2 = 5) OR
       (r1 = 5 AND r2 = 8) OR
       (r1 = 3 AND r2 = 8) OR
       (r1 = 5 AND r2 = 3) OR
       (r1 = 3 AND r2 = 5) OR
       (r1 = 8 AND r2 = 3)
)
order by (case when (tcount = 16 AND r1 = 3 AND r2 = 5 AND r3 = 8)
               then 1
               else 2
          end);

Затем создайте индекс на:

create index rgp_r1_r1_r3_tcount on rgp(r1, r2, r3, tcount);

Этот индекс должен работать с обоими подзапросами. Я не думаю, что MySQL достаточно умен, чтобы использовать его с исходными данными, но это тоже стоит попробовать.

1
Gordon Linoff 24 Фев 2014 в 16:40