递归UNION ALL解析字符串需要很长时间

时间:2014-08-15 19:15:05

标签: sql sql-server recursion union common-table-expression

我正在尝试加速这个递归的UNION ALL,如下所示,但我想不出怎么做。也许是一段时间循环,但我不确定。移动数据存储为一长串编码的移动数据,并且脚本递归地调用select语句来解析/提取该数据,然后将其全部转换。

我真的想更多地了解加快所有递归联合或寻找其他方法。我不相信索引是一个问题所以这不是一个可能的解决方案。

"的RouteData"是由固定长度间隔解析的长字符串。

以下是编码数据的示例:

ScenarioPID : 3
LegID  :1
RoutePart : 0x0000000000000000000100000000000000000000000000
RouteData : 0x40323AAAAAAAAAAB00013FA6FFD663CCA3310000001F00403 ... (goes on)
cnt : 37
sequence : 1
StartTime : 8828

对于一个曲目,最终输出数据如下所示。

ScenarioPID LegID   sequence    TrackID Offset  TimeOffset  Length  StartTime
3             1        1           1      0         0        6300    8828
3             1        2           1      0.0449    31       6300    8828
3             1        3           1      0.8942    325      6300    8828
3             1        4           1      0.9736    356      6300    8828
3             1        5           1      1         369      6300    8828

USE nss_demo;

DECLARE @scenario1 INT;
DECLARE @DAY_START INT;
DECLARE @DAY_END INT;
DECLARE @TRAIN_TYPE VARCHAR(50);
DECLARE @TRACK_TYPE VARCHAR(50);

SET @scenario1 = 3;
SET @DAY_START = 0;
SET @DAY_END = 7;
SET @TRAIN_TYPE = 'Empty Train';
SET @TRACK_TYPE = 'East Track';

DECLARE @KM_START INT;
DECLARE @KM_END INT;

SET @KM_START = 0;
SET @KM_END = 200;

WITH movement
     AS (SELECT m.scenariopid,
                m.legid,
                Substring(routedata, 1, 23)                   AS RoutePart,
                Substring(routedata, 24, Len(routedata) - 23) AS RouteData,
                Len(routedata) / 23 - 1                       AS cnt,
                1                                             AS sequence,
                m.starttime
         FROM   output.movement m
         WHERE  scenariopid = @scenario1
                AND m.starttime BETWEEN ( @DAY_START * 86400 ) AND
                                        ( @DAY_END * 86400 )
         UNION ALL
         SELECT scenariopid,
                legid,
                Substring(m1.routedata, 1, 23)                      AS RoutePart
                ,
                Substring(m1.routedata, 24,
                Len(m1.routedata) - 23) AS RouteData,
                Len(m1.routedata) / 23 - 1                          AS cnt,
                sequence + 1                                        AS sequence,
                m1.starttime
         FROM   movement m1
         WHERE  m1.cnt > 0),
     casttable
     AS (SELECT tt.scenariopid,
                tt.legid,
                tt.sequence,
                tt.trackid,
                tt.offset,
                tt.timeoffset,
                tr.[length],
                tt.starttime
         FROM   (SELECT scenariopid,
                        legid,
                        sequence,
                        Cast(trackidbin AS SMALLINT) AS TrackID,
                        Sign(Cast(offsetbin AS BIGINT)) *
                        ( 1.0 +
                        ( Cast(offsetbin AS BIGINT) & 0x000FFFFFFFFFFFFF ) *
                        Power(Cast(2 AS FLOAT), -52) )
                        *
                        Power(Cast(2 AS FLOAT), ( Cast(offsetbin AS BIGINT) &
                                                  0x7ff0000000000000
                                                ) /
                        0x0010000000000000
                        - 1023)                      AS Offset,
                        Cast(timebin AS INT)         AS TimeOffset,
                        starttime                    AS StartTime
                 FROM   (SELECT legid,
                                scenariopid,
                                sequence,
                                Substring(routepart, 9, 2)  AS TrackIDBin,
                                Substring(routepart, 11, 8) AS OffsetBin,
                                Substring(routepart, 19, 4) AS TimeBin,
                                starttime
                         FROM   movement) t) tt
                INNER JOIN input.track tr
                        ON tr.trackid = tt.trackid
                           AND tr.scenariopid = tt.scenariopid)
SELECT *
FROM   casttable
ORDER  BY legid,
          sequence
OPTION (maxrecursion 20000) 

1 个答案:

答案 0 :(得分:0)

使用Numbers Table(以下从零开始假定)创建CTE 移动,如下所示:

WITH movement
     AS (SELECT m.scenariopid,
                m.legid,
                Substring(routedata, n.N*23 + 1, 23)  AS RoutePart,
                n.N                                   AS cnt,
       --         1                                   AS sequence,  -- use a row_number function here instead, as per your vendor.
                m.starttime
         FROM   output.movement m
         JOIN Numbers n
            on n < Len(routedata) / 23 
         WHERE  scenariopid = @scenario1
                AND m.starttime BETWEEN ( @DAY_START * 86400 ) AND
                                        ( @DAY_END * 86400 )
),
-- etc.

如果您没有静态数字表,my answer here将演示如何在CTE中动态创建数字表。

相关问题