У меня есть таблица под названием PRODUCT_CATEGORY, который имеет составной первичный ключ, состоящий из 2-х целого числа без знака полех и без каких-либо дополнительных вторичных индексов:
create table product_category
(
prod_id int unsigned not null,
cat_id mediumint unsigned not null,
primary key (cat_id, prod_id) -- note the clustered composite index !!
)
engine = innodb;
в таблице в настоящее время имеет 125 миллионов строк
select count(*) as c from product_category;
c
=
125,524,947
со следующими индексными/кардинальностями:
show indexes from product_category;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality
===== ========== ======== ============ =========== ========= ===========
product_category 0 PRIMARY 1 cat_id A 1162276
product_category 0 PRIMARY 2 prod_id A 125525826
Если я выполнить запрос, похожий на твой (первый запуск ничего не кэшируется и с холодными/пустыми буферами):
select
prod_id, count(*) as c
from
product_category
where
cat_id between 1600 and 2000 -- using between to include a wider range of data
group by
prod_id
having c = (
select count(*) as c from product_category
where cat_id between 1600 and 2000
group by prod_id order by c desc limit 1
)
order by prod_id;
I получить следующие результаты:
(cold run)
+---------+---+
| prod_id | c |
+---------+---+
| 34957 | 4 |
| 717812 | 4 |
| 816612 | 4 |
| 931111 | 4 |
+---------+---+
4 rows in set (0.18 sec)
(2nd run)
+---------+---+
| prod_id | c |
+---------+---+
| 34957 | 4 |
| 717812 | 4 |
| 816612 | 4 |
| 931111 | 4 |
+---------+---+
4 rows in set (0.14 sec)
объяснить план выглядит следующим образом:
+----+-------------+------------------+-------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+-------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
| 1 | PRIMARY | product_category | range | PRIMARY | PRIMARY | 3 | NULL | 194622 | Using where; Using index; Using temporary; Using filesort |
| 2 | SUBQUERY | product_category | range | PRIMARY | PRIMARY | 3 | NULL | 194622 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+------------------+-------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
Если я запускаю запрос regilero в:
SELECT c,prod_id
FROM (
SELECT c,prod_id,CASE WHEN @mmax<=c THEN @mmax:=c ELSE 0 END 'mymax'
FROM (
SELECT COUNT(*) as c, prod_id FROM product_category WHERE
cat_id between 1600 and 2000
GROUP BY prod_id
ORDER BY c DESC
) res1
,(SELECT @mmax:=0) initmax
ORDER BY c DESC
) res2 WHERE mymax>0;
Я получаю следующие результаты:
(cold)
+---+---------+
| c | prod_id |
+---+---------+
| 4 | 931111 |
| 4 | 34957 |
| 4 | 717812 |
| 4 | 816612 |
+---+---------+
4 rows in set (0.17 sec)
(2nd run)
+---+---------+
| c | prod_id |
+---+---------+
| 4 | 34957 |
| 4 | 717812 |
| 4 | 816612 |
| 4 | 931111 |
+---+---------+
4 rows in set (0.13 sec)
Explain, план выглядит следующим образом:
+----+-------------+------------------+--------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+--------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 92760 | Using where |
| 2 | DERIVED | <derived4> | system | NULL | NULL | NULL | NULL | 1 | Using filesort |
| 2 | DERIVED | <derived3> | ALL | NULL | NULL | NULL | NULL | 92760 | |
| 4 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 3 | DERIVED | product_category | range | PRIMARY | PRIMARY | 3 | NULL | 194622 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+------------------+--------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
Наконец, попробовав кибервик I Подход:
drop procedure if exists cyberkiwi_variant;
delimiter #
create procedure cyberkiwi_variant()
begin
create temporary table tmp engine=memory
select prod_id, count(*) as c from
product_category where cat_id between 1600 and 2000
group by prod_id order by c desc;
select max(c) into @max from tmp;
select * from tmp where c = @max;
drop temporary table if exists tmp;
end#
delimiter ;
call cyberkiwi_variant();
Я получаю следующие результаты:
(cold and 2nd run)
+---------+---+
| prod_id | c |
+---------+---+
| 816612 | 4 |
| 931111 | 4 |
| 34957 | 4 |
| 717812 | 4 |
+---------+---+
4 rows in set (0.14 sec)
Explain, план выглядит следующим образом:
+----+-------------+------------------+-------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+-------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
| 1 | SIMPLE | product_category | range | PRIMARY | PRIMARY | 3 | NULL | 194622 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+------------------+-------+---------------+---------+---------+------+--------+-----------------------------------------------------------+
Таким образом, кажется, что все методы тестируемых имеют ок. те же промежутки времени от 0.14 до 0.18 секунд, которые кажутся мне довольно эффективными, учитывая размер таблицы и количество запросов.
Надеюсь, что это поможет - http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html
Как обновить данные? Можно ли хранить скопления? – Matthew
Это очень похоже на [этот вопрос] (http://stackoverflow.com/q/2015406/119477), как ни странно, принятый ответ OP был в порядке с потерей связей для max –
, какой тип двигателя вы используете, а какой два поля имеют самую низкую мощность - есть что-то типа type_id? –