Переношу систему анализа статистики с MySQL (MariaDB 10) на MS SQL 2014 и обнаружил странную вещь. Обычно я использовал индексы с одним и несколькими полями для большинства операций: база данных статистики содержит около 60 миллионов событий на 4-ядерном компьютере, а анализ включает воронки, сегментацию событий, когортный анализ, ключевые показатели эффективности и многое другое, поэтому это может быть медленным. иногда.
Но я был очень удивлен, когда выполнил несколько последовательностей запросов из MS SQL, а затем удалил все индексы (кроме основного кластеризованного id): я увидел, что время выполнения даже уменьшилось! Я перезапускал сервер (кеш очищался), но после каждого перезапуска результат был одинаков - мои запросы работают быстрее без индексов (фактически скорость та же, но не тратится время на ручное создание индексов).
Я предполагаю, что MS SQL создает для меня неявные индексы, но в этом случае похоже, что я должен удалить все создание индексов из моих запросов? В MySQL вы можете ясно видеть, что добавление индексов действительно работает. Означает ли это поведение MS SQL, что мне больше не нужно заботиться об индексах? Я сделал несколько тестов со своими запросами, и кажется, что индексы почти не влияют на время выполнения. Последний раз, когда я имел дело с MS SQL, это было очень давно, и это был MS SQL 2000, так что, может быть, MSFT разработала чертов ИИ за последние 15 лет? :)
На всякий случай этот тестовый код sql (сгенерированный серверной частью для внешнего интерфейса) приведен ниже. Короче говоря, он создает графические данные для определенного типа событий за последние 3 месяца с течением времени, а затем выполняет сегментацию по одному параметру. Он создает временную таблицу из основной таблицы событий с заданными пользователем ограничениями (период времени, параметры), создает еще несколько временных таблиц и индексов, выполняет несколько объединений и возвращает окончательный результат выбора:
select min(tmstamp), max(tmstamp)
from evt_db.dbo.events
where ( ( source = 3 )
and ( event_id=24 )
and tmstamp > 1451606400
AND tmstamp < 1458000000
);
select min(param1), max(param1), count(DISTINCT(param1))
from evt_db.dbo.events
WHERE ( ( source = 3 )
AND ( event_id=24 )
AND tmstamp > 1451606400
AND tmstamp < 1458000000
);
create table #_tmp_times_calc_analyzer_0_0 (
tm_start int,
tm_end int,
tm_origin int,
tm_num int
);
insert into #_tmp_times_calc_analyzer_0_0 values
( 1451606400, 1452211200, 1451606400, 0 ),
( 1452211200, 1452816000, 1452211200, 1 ),
( 1452816000, 1453420800, 1452816000, 2 ),
( 1453420800, 1454025600, 1453420800, 3 ),
( 1454025600, 1454630400, 1454025600, 4 ),
( 1454630400, 1455235200, 1454630400, 5 ),
( 1455235200, 1455840000, 1455235200, 6 ),
( 1455840000, 1456444800, 1455840000, 7 ),
( 1456444800, 1457049600, 1456444800, 8 ),
( 1457049600, 1457654400, 1457049600, 9 ),
( 1457654400, 1458259200, 1457654400, 10 );
А также...
CREATE INDEX tm_num ON _tmp_times_calc_analyzer_0_0 (tm_num);
SELECT id, t1.uid, tmstamp, floor((tmstamp - 1451606400) / 604800) period_num,
param1 into #_tmp_events_view_analyzer_0_0
FROM evt_db.dbo.events t1
WHERE ( ( source = 3 )
AND ( event_id=24 )
AND tmstamp > 1451606400
AND tmstamp < 1458000000
);
CREATE INDEX uid ON _tmp_events_view_analyzer_0_0 (uid);
CREATE INDEX period_num ON _tmp_events_view_analyzer_0_0 (period_num);
CREATE INDEX tmstamp ON _tmp_events_view_analyzer_0_0 (tmstamp);
CREATE INDEX _index_param1 ON _tmp_events_view_analyzer_0_0 (param1);
create table #_tmp_median_analyzer_0_0 (ts int );
insert into #_tmp_median_analyzer_0_0
select distinct(param1) v
from #_tmp_events_view_analyzer_0_0
where param1 is not null
order by v ;
select tm_origin, count(distinct uid), count(distinct id)
from #_tmp_times_calc_analyzer_0_0
left join #_tmp_events_view_analyzer_0_0 ON period_num = tm_num
GROUP BY tm_origin;
select top 600 (param1) seg1, count(distinct uid), count(distinct id)
from #_tmp_events_view_analyzer_0_0
GROUP BY param1
order by 1 asc;
А также...
select seg1, tm_origin, count(distinct uid), count(distinct id)
from
( SELECT (param1) seg1, tm_origin, uid, id
from #_tmp_times_calc_analyzer_0_0
left join #_tmp_events_view_analyzer_0_0 ON period_num = tm_num
group by param1, tm_origin, uid, id
) t
GROUP BY seg1, tm_origin;
select min(param1), max(param1), round(avg(param1),0)
from #_tmp_events_view_analyzer_0_0;
DECLARE @c BIGINT = (SELECT COUNT(*) FROM #_tmp_median_analyzer_0_0);
SELECT round(AVG(1.0 * ts),0)
FROM
( SELECT ts
FROM #_tmp_median_analyzer_0_0
ORDER BY ts OFFSET (@c - 1) / 2 ROWS
FETCH NEXT 1 + (1 - @c % 2) ROWS ONLY
) AS median_val;