Я относительно новичок в MySQL, и с тех пор я пытаюсь улучшить запрос, который выполняется для большой таблицы (> 70 млн. Строк). Хорошие новости, я получил правильный результат. К сожалению, это занимает около 7 минут для расчета, что, на мой взгляд, способ долго. Я искал способы улучшить запросы и придумал многостолбцовый индекс таблицы, но теперь я как-то застрял и не знаю, как еще улучшить.
Таблица состоит из 5 столбцов, все они представляют интерес. Столбцы state , cur , min и max являются INT. В столбце sample хранятся некоторые имена, которые несколько раз в этом столбце. В каждой строке хранится информация одного состояния одного образца. Каждый образец имеет миллионы разных состояний. Таблица выглядит следующим образом:
samples state cur min max
Sample1 1 58 12 110
Sample1 0 8 12 110
Sample2 1 70 150 190
Sample4 2 10 1 20
Sample3 2 80 50 70
Sample6 2 3 1 10
Sample5 0 18 21 90
Sample5 1 22 21 90
.
.
.
Теперь я хочу выполнить некоторую статистику для таблицы: Сколько раз будет состояние с cur между мин и макс . Я хочу получить эти цифры для каждого образца. Кроме того, я также хочу вычислить относительное количество состояний 1, 2 и 3. для каждого образца.
Полученная таблица выглядит следующим образом:
total amount state 0 state 1 state 2 state 0 % state 1 % state 2 %
Sample1 14504366 13199105 961629 343632 91.0009 6.6299 2.3692
Sample2 13873909 12628523 926846 318540 91.0235 6.6805 2.2960
Sample3 10919017 9231997 828767 858253 84.5497 7.5901 7.8602
Sample4 10148540 8604527 768220 775793 84.7859 7.5698 7.6444
Sample5 14130796 12382867 1078724 669205 87.6304 7.6339 4.7358
Sample6 11307051 9947652 871388 488011 87.9774 7.7066 4.3160
Я получил результат по используя следующий код:
# state, cur, min and max are INT
# "samples" is Varchar40
# build the index
ALTER TABLE data_table ADD INDEX `index_name` (state, cur, min, max, samples);
# query
SELECT t.samples,
COUNT(t.state) AS "total amount",
amount_0 AS "state 0",
amount_1 AS "state 1",
amount_2 AS "state 2",
amount_0 / COUNT(t.state) * 100 AS "state 0 %",
amount_1 / COUNT(t.state) * 100 AS "state 1 %",
amount_2 / COUNT(t.state) * 100 AS "state 2 %"
FROM data_table t
JOIN
(
SELECT samples, COUNT(state) as amount_0
FROM data_table
WHERE state = 0 AND cur > min + 15 AND cur < max -20
GROUP BY samples
) tmp0 ON tmp0.samples = t.samples
JOIN
(
SELECT samples, COUNT(state) as amount_1
FROM data_table
WHERE state = 1 AND cur > min + 15 AND cur < max -20
GROUP BY samples
) tmp1 ON tmp1.samples = t.samples
JOIN
(
SELECT samples, COUNT(state) as amount_2
FROM data_table
WHERE state = 2 AND cur > min + 15 AND cur < max -20
GROUP BY samples
) tmp2 ON tmp2.samples = t.samples
WHERE cur > min + 15 AND cur < max -20
GROUP BY t.samples;
EXPLAIN возвращает следующий вывод:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t [NULL] index index_name index_name 143 [NULL] 73647812 11.11 Using where; Using index; Using temporary; Using filesort
1 PRIMARY <derived4> [NULL] ref <auto_key0> <auto_key0> 123 db.t.Sample 10 100 [NULL]
1 PRIMARY <derived2> [NULL] ref <auto_key0> <auto_key0> 123 db.t.Sample 10 100 [NULL]
1 PRIMARY <derived3> [NULL] ref <auto_key0> <auto_key0> 123 db.t.Sample 10 100 [NULL]
4 DERIVED data_table [NULL] ref index_name index_name 5 const 7547114 11.11 Using where; Using index; Using temporary; Using filesort
3 DERIVED data_table [NULL] ref index_name index_name 5 const 15150796 11.11 Using where; Using index; Using temporary; Using filesort
2 DERIVED data_table [NULL] ref index_name index_name 5 const 36823906 11.11 Using where; Using index; Using temporary; Using filesort
Я думаю, что большой проблемой являются детали JOIN , где, вероятно, индексы теряются. Вторым этапом, требующим много времени, может быть - если я правильно понимаю - использование WHERE , которое приведет к объединению всего, а затем удалит строки, которые не соответствуют регистру, на втором этапе. Это отнимает много времени и этого можно избежать, используя ON вместо WHERE (?). Моя проблема в том, что я не знаю, как реализовать обходной путь. Поэтому я надеюсь, что вы можете помочь мне.