索引不会影响ms sql 2014 VS mysql(mariaDB 10)中的时间执行

时间:2016-03-15 21:51:14

标签: mysql sql-server-2014 database-performance database-indexes

我将统计分析系统从MySQL(MariaDB 10)移植到MS SQL 2014,我发现了一件奇怪的事情。通常我以前使用单场和多场索引进行大多数操作:统计数据库在4核PC上容纳大约6千万个事件,分析包括漏斗,事件分段,队列分析,KPI等等,所以它可能很慢有时。

但是当我从MS SQL执行了几个查询序列然后删除所有索引(主要的clastered id除外)时,我感到非常惊讶:我看到执行时间甚至减少了!我重新启动了服务器(缓存已清除),但每次重启结果都相似之后 - 我的查询在没有索引的情况下工作得更快(实际速度相同,但没有时间花在创建手动索引上)。

我想MS SQL为我创建了隐式索引,但在这种情况下看起来我应该从查询中删除所有索引创建?在MySQL中,您可以清楚地看到添加索引确实有效。这种MS SQL行为是否意味着我不再需要关心索引了?我用我的查询做了几次测试,看起来索引几乎不会影响执行时间。上次我用MS SQL处理了很久以前它是MS SQL 2000,所以也许MSFT开发了f ** n' AI在过去的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; 

1 个答案:

答案 0 :(得分:0)

evt_db.dbo.events需要INDEX(source, event, tmstamp)tmstamp需要{3}。对于MySQL,前两个SELECTs将完全在索引中运行(因为它是一个“覆盖”索引)。 sourceevent可以按任意顺序排列。

稍后,您有类似的SELECT,但它也有id, t1.uid。你可以为它制作这个覆盖索引:INDEX(source, event, tmstamp, uid, id)。同样,tmstamp必须在列表中排在第三位。

select top 600 (param1) seg1, count(distinct uid), count(distinct id) ...可能会从INDEX(param1, uid, id)中受益,其中param1必须是第一位。

您列出的其他索引可能根本没用。您尝试了哪些索引?

MySQL和其他数据库之间的一个区别 - MySQL几乎从不在查询中使用多个索引。而且,根据我的经验,MySQL的选择是“明智的”。也许MSSql尝试使用两个索引太难了,当简单地扫描表时工作就会少一些。