Как оптимизировать COUNT(*)?

Планируется очень большая таблица с текстовым полем. Нужно часто узнавать, имеется ли в ней больше 10 строк, удовлетворяющих сложному полнотекстовому условию.

Если делать запрос
SELECT COUNT(*) AS num_rows FROM my_table WHERE [проверяемое условие];

то будут искаться и подсчитываться все строки, удовлетворяющие условию.

Можно ли как-то оптимизировать эту задачу? Добавление в этот запрос LIMIT ничего не дает. Все равно считает общее количество подходящих строк.

Есть мысль делать так:
SELECT COUNT(*) AS num_rows 
FROM ( SELECT `id` FROM my_table WHERE [проверяемое условие] LIMIT 11 ) AS good_rows;

Будет ли от этого оптимизация или будет еще хуже?
  • Вопрос задан
  • 589 просмотров
Решения вопроса 2
firedragon
@firedragon
Не джун-мидл-сеньор, а трус-балбес-бывалый.
создайте таблицу в ней что то типа rows_matched
при инсерте нужной фразы добавляйте 1
при удалении вычитайте

по итогу у вас вместо тяжелого селекта очень легкий запрос
Ответ написан
Комментировать
@galaxy
Будет ли от этого оптимизация или будет еще хуже?

В описанной ситуации, скорее всего, будет.
Вот пример для таблицы на 5 млн строк:
> EXPLAIN ANALYZE select count(*) from u where val like 'xz%';
-> Aggregate: count(0)  (actual time=358.829..358.829 rows=1 loops=1)
    -> Filter: (u.val like 'xz%')  (cost=1081.88 rows=4995) (actual time=0.388..358.196 rows=4995 loops=1)
        -> Index range scan on u using u_val  (cost=1081.88 rows=4995) (actual time=0.383..356.709 rows=4995 loops=1)

> EXPLAIN ANALYZE select count(*) from (select id from u where val like 'zx%' limit 11) q;
-> Aggregate: count(0)  (actual time=1.609..1.609 rows=1 loops=1)
    -> Table scan on q  (actual time=0.002..0.005 rows=11 loops=1)
        -> Materialize  (actual time=1.594..1.601 rows=11 loops=1)
            -> Limit: 11 row(s)  (actual time=0.089..1.560 rows=11 loops=1)
                -> Filter: (u.val like 'zx%')  (cost=1183.58 rows=5465) (actual time=0.088..1.555 rows=11 loops=1)
                    -> Index range scan on u using u_val  (cost=1183.58 rows=5465) (actual time=0.082..1.537 rows=11 loops=1)


Ускорение более чем в 200 раз. Разумеется, тут важно, что строк, подходящих под условие, в таблице значительно больше 10 - в данном случае 5.5 тысяч. Если подходящих строк будет в пределах нескольких десятков, разница будет не особо заметна.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
SilenceOfWinter
@SilenceOfWinter
та еще зажигалка...
SELECT СOUNT(*) as num_rows FROM my_table WHERE [проверяемое условие]

SELECT id FROM my_table WHERE [проверяемое условие] LIMIT 10

SELECT COUNT(*) AS num_rows  FROM shop_category WHERE id IN (SELECT id FROM shop_category WHERE [проверяемое условие])
Ответ написан
Комментировать
AgentSmith
@AgentSmith
Это мой правильный ответ на твой вопрос
Ещё дополнение.
Не нужно использовать COUNT(*)
надо использовать всего лишь одно поле, например, COUNT(id)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы