Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 数值范围优化_Php_Mysql_Algorithm_Nested Sets_Modified Preorder Tree T - Fatal编程技术网

Php 数值范围优化

Php 数值范围优化,php,mysql,algorithm,nested-sets,modified-preorder-tree-t,Php,Mysql,Algorithm,Nested Sets,Modified Preorder Tree T,我有一套数值范围,我想优化 以下是初始值的简单示例: Start End 9 12 1 2 60 88 10 11 79 80 优化后的输出结果: Start End 1 2 9 12 60 88 这些是MySQL数据库中存储的修改后的前序树遍历嵌套集数据的左值和右值。我使用它们从结果中排除非活动分支,并且目前根本没有优化范围。我想在使用前优化范围可能会提高性能 更多信息 这些

我有一套数值范围,我想优化

以下是初始值的简单示例:

Start    End
9        12
1        2
60       88
10       11
79       80
优化后的输出结果:

Start    End
1        2
9        12
60       88
这些是MySQL数据库中存储的修改后的前序树遍历嵌套集数据的左值和右值。我使用它们从结果中排除非活动分支,并且目前根本没有优化范围。我想在使用前优化范围可能会提高性能

更多信息


这些值被传递到查询中,以便使用NOT BEVER子句排除树中的非活动分支。我认为我可以通过使用一组最小的范围来优化查询的性能。

将它们放在一个排序列表中。标记排序列表中哪些元素表示范围开始,哪些元素表示范围结束。首先根据值对列表进行排序;但是,请确保范围开始在范围结束之前。这可能涉及某种类型的结构,可以根据给定的键进行排序。我不知道php的细节

现在,从头到尾遍历列表。留个柜台,c。当你通过一个范围开始时,增加c。当你通过一个范围结束时,递减c

当c从0变为1时,这是最终集合中范围的开始。当c从1变为0时,这是一个范围的结束


编辑::如果数据库表中的某个位置已经有了范围,您可能可以构造一个SQL查询来再次执行上面的第一步,确保在范围结束点之前返回范围起始点。

下面是一个简单的实现:

// I picked this format because it's convenient for the solution
// and because it's very natural for a human to read/write
$ranges = array(
  9    =>    12,
  1    =>    2,
  60   =>    81,
  10   =>    11,
  79   =>    88);

ksort($ranges);
$count = count($ranges);
$prev = null; // holds the previous start-end pair

foreach($ranges as $start => $end) {
    // If this range overlaps or is adjacent to the previous one
    if ($prev !== null && $start <= $prev[1] + 1) {
        // Update the previous one (both in $prev and in $ranges)
        // to the union of its previous value and the current range
        $ranges[$prev[0]] = $prev[1] = max($end, $prev[1]);

        // Mark the current range as "deleted"
        $ranges[$start] = null;
        continue;
    }

    $prev = array($start, $end);
}

// Filter all "deleted" ranges out
$ranges = array_filter($ranges);
限制/注意事项:

范围边界必须足够小,以适合整数。 如果结束边界为0,此示例将错误地从最终结果中删除任何范围。如果您的数据可以合法地包含这样一个范围,请提供对数组_filter的适当回调:函数$item{return$item==null;}。

注意:这不适用于负整数

或者像这样使用它

$rres = optimizeRangeArray($ranges);

$out = "<pre>Start    End<br />";
foreach($rres as $range=>$bounds) {
  $out .= str_pad($bounds[0], 9, ' ') . str_pad($bounds[1], 9, ' ') . "<br />";
  }
$out .= "</pre>";
echo $out;

下面是一个SQL,它将返回您想要的内容

SELECT s.* 
FROM sample s LEFT JOIN 
     sample s2 ON s.Start > s2.Start AND s.Start < s2.End 
WHERE s2.start IS NULL;
当然,您可以使用上述SQL创建视图、将数据移动到另一个表或删除行

注意:我不太清楚你为什么要做这种“优化”

编辑: 查询可以重写为


这将为EXISTS创建不同的执行计划2xsimple select vs primary/dependent子查询,因此性能可能会有所不同。这两个查询都将在开始时使用索引,如果存在,则在结束时使用索引。

因此您希望将一组范围折叠为最小范围集。您正在选择嵌套集中的顶层。这可以在SQL中完成。@Unreason-您能用一个查询示例详细说明一下吗?现在没时间了,看看它是否足以将范围从一个列表开始,范围从另一个列表结束;然后迭代它们,使用两个指针,并将指向较低数字的指针向前推进。这样,关于范围开始和结束的相对顺序的问题也就消失了,在SQL中应该更容易进行两个查询,一个查询范围开始,一个查询范围结束,然后在SQL查询中对它们进行排序。这种方法适用于查找范围并集的一般问题。您应该注意,OP特别要求来自“嵌套集”的范围,其中范围要么是正确的子集,要么没有交叉点,因此嵌套。这非常有效!我现在注意到,我有相邻的节点,我也想合并。1,2和3,4将变成1,4。@Sonny,好吧-这是一个不同的问题,对于这个问题,其他提出的解决方案都是很好的算法。然而,我有点困惑,你的目的是什么?在一般使用场景中优化嵌套集是没有必要的-它已经是一个优化的数据结构,可以利用DB索引进行递归查询。我想我会在有机会的时候创建一个新的帖子。我可能做得不对,或者我目前的解决方案可能是最优的。
$rres = optimizeRangeArray($ranges);

$out = "<pre>Start    End<br />";
foreach($rres as $range=>$bounds) {
  $out .= str_pad($bounds[0], 9, ' ') . str_pad($bounds[1], 9, ' ') . "<br />";
  }
$out .= "</pre>";
echo $out;
Start    End
1        2
9        12
60       88
mysql> CREATE TABLE sample (Start INT, End INT);

mysql> INSERT sample VALUES (9,12),(1,2),(60,88),(10,11),(79,80);

mysql> SELECT * 
    -> FROM sample s 
    -> WHERE NOT EXISTS (SELECT 1 
    ->                   FROM sample 
    ->                   WHERE s.Start > Start AND s.Start < End);
+-------+------+
| Start | End  |
+-------+------+
|     9 |   12 |
|     1 |    2 |
|    60 |   88 |
+-------+------+
SELECT s.* 
FROM sample s LEFT JOIN 
     sample s2 ON s.Start > s2.Start AND s.Start < s2.End 
WHERE s2.start IS NULL;