Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.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
MySQL:从向量中获取具有完全相同数据的DB行_Mysql - Fatal编程技术网

MySQL:从向量中获取具有完全相同数据的DB行

MySQL:从向量中获取具有完全相同数据的DB行,mysql,Mysql,我有这张桌子: CREATE TABLE Table1 (`id` int, `x_id` int) ; INSERT INTO Table1 (`id`, `x_id`) VALUES (1, 90), (1, 91), (1, 92), (2, 90), (2, 91), (2, 92), (2, 93) ; 我有一个向量[90,91,92]。我的问题很简单: SELECT DISTINCT(id) FROM Tab

我有这张桌子:

CREATE TABLE Table1
    (`id` int, `x_id` int)
;

INSERT INTO Table1
    (`id`, `x_id`)
VALUES
    (1, 90),
    (1, 91),
    (1, 92),
    (2, 90),
    (2, 91),
    (2, 92),
    (2, 93)
;
我有一个向量[90,91,92]。我的问题很简单:

SELECT DISTINCT(id) FROM Table1 WHERE x_id IN ( 90,91,92);

正确地返回这两个参数。如何仅获取x_id值与向量完全匹配的id

这里有一种方法假设id和x_id的每个组合都是唯一的:

SELECT id 
  FROM table1 
 GROUP 
    BY id 
HAVING SUM(x_id IN (90,91,92)) = COUNT(x_id)  
   AND COUNT(*) = 3;

这里有一种方法假设id和x_id的每个组合都是唯一的:

SELECT id 
  FROM table1 
 GROUP 
    BY id 
HAVING SUM(x_id IN (90,91,92)) = COUNT(x_id)  
   AND COUNT(*) = 3;

我喜欢假设数据集中有数百万行,因为这会严重影响查询设计

考虑到这一点,您可以执行以下操作:

SELECT id, 
SUM(x_id IN (90,91,92)) AS score,
SUM(1) AS count
FROM Table1
WHERE id IN (
    SELECT id FROM Table1 WHERE x_id IN (90,91,92)
)
GROUP BY id
HAVING score = count AND count = 3;

只考虑具有XYID匹配90, 91或92的行。它计算每个id匹配的x_id值的分数。它还计算每个id的不同x_id值的计数。这有助于我们排除具有90、91和92值,但也具有其他值的id

精确的向量匹配的分数等于计数

这种方法在有数百万行的表上应该更有效,因为只有这些行的子集将引用至少一个目标值

它假设每个id,x_id元组都是唯一的

编辑:

修复了示例中的HAVING count=3问题,如注释中报告的

当使用这样的子查询时,请确保使用的是最新版本的MySQL。MySQL 5.5及更早版本的子查询性能较差,这是因为查询规划器忽略键并进行昂贵的扫描

为了演示额外子查询的性能改进,我们可以生成一组样本数据插入到表1中。下面是一个简单的PHP脚本,它使用长度为2-5、值介于1-100之间的随机向量生成100000行:

<?php
$possible_values = range(1,100);

foreach(range(1,100000) as $id) {
    $vector = array_rand($possible_values, mt_rand(2,5));

    $values = array_map(function($x_id) use ($id) {
        return sprintf("(%d, %d)", $id, $x_id);
    }, $vector);

    echo sprintf("INSERT INTO Table1 (id, x_id) VALUES %s;\n",
        implode(',', $values)
    );
}
让我们比较一下子查询优化的好处,找到一个短向量:

mysql> SELECT SQL_NO_CACHE id, 
    -> SUM(x_id IN (6,25)) AS score,
    -> SUM(1) AS count
    -> FROM Table1
    -> WHERE id IN (
    -> SELECT id FROM Table1 WHERE x_id IN (6,25)
    -> )
    -> GROUP BY id
    -> HAVING score = count AND count = 2;
+-------+-------+-------+
| id    | score | count |
+-------+-------+-------+
| 15265 |     2 |     2 |
| 40816 |     2 |     2 |
| 75000 |     2 |     2 |
| 75239 |     2 |     2 |
| 83498 |     2 |     2 |
+-------+-------+-------+
5 rows in set (0.04 sec)

mysql> SELECT SQL_NO_CACHE id 
    -> FROM table1 
    -> GROUP BY id 
    -> HAVING SUM(x_id IN (6,25)) = COUNT(x_id) 
    -> AND COUNT(*) = 2;
+-------+
| id    |
+-------+
| 15265 |
| 40816 |
| 75000 |
| 75239 |
| 83498 |
+-------+
5 rows in set (0.14 sec)
优化速度加快了100毫秒,占未优化查询时间的29%

你可以通过解释来了解原因

未优化我们正在扫描几乎整个表格:

mysql> explain SELECT SQL_NO_CACHE id  FROM table1  GROUP BY id  HAVING SUM(x_id IN (6,25)) = COUNT(x_id)  AND COUNT(*) = 2 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table1
   partitions: NULL
         type: index
possible_keys: id
          key: id
      key_len: 10
          ref: NULL
         rows: 338846
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)
优化:

mysql> explain SELECT SQL_NO_CACHE id,  SUM(x_id IN (6,25)) AS score, SUM(1) AS count FROM Table1 WHERE id IN ( SELECT id FROM Table1 WHERE x_id IN (6,25) ) GROUP BY id HAVING score = count AND count = 2 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: <subquery2>
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
     filtered: 100.00
        Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: Table1
   partitions: NULL
         type: ref
possible_keys: id
          key: id
      key_len: 5
          ref: <subquery2>.id
         rows: 3
     filtered: 100.00
        Extra: Using index
*************************** 3. row ***************************
           id: 2
  select_type: MATERIALIZED
        table: Table1
   partitions: NULL
         type: range
possible_keys: x_id,id
          key: x_id
      key_len: 5
          ref: NULL
         rows: 6874
     filtered: 100.00
        Extra: Using index condition
3 rows in set, 1 warning (0.00 sec)
在优化过程中,我们可以将聚合的行子集从~338846限制到~6874。MySQL要做的工作要少得多

对于较长的向量(如19,61,62,96),优化的查询运行速度为80ms,而表扫描速度几乎是150ms的两倍


额外的复杂性可能不值得节省100毫秒,但如果Table1有数百万行,那么与聚合整个表的未优化方法相比,优化查询的性能将变得非常明显。

我喜欢假设数据集中有数百万行,因为这严重影响了查询设计

考虑到这一点,您可以执行以下操作:

SELECT id, 
SUM(x_id IN (90,91,92)) AS score,
SUM(1) AS count
FROM Table1
WHERE id IN (
    SELECT id FROM Table1 WHERE x_id IN (90,91,92)
)
GROUP BY id
HAVING score = count AND count = 3;

只考虑具有XYID匹配90, 91或92的行。它计算每个id匹配的x_id值的分数。它还计算每个id的不同x_id值的计数。这有助于我们排除具有90、91和92值,但也具有其他值的id

精确的向量匹配的分数等于计数

这种方法在有数百万行的表上应该更有效,因为只有这些行的子集将引用至少一个目标值

它假设每个id,x_id元组都是唯一的

编辑:

修复了示例中的HAVING count=3问题,如注释中报告的

当使用这样的子查询时,请确保使用的是最新版本的MySQL。MySQL 5.5及更早版本的子查询性能较差,这是因为查询规划器忽略键并进行昂贵的扫描

为了演示额外子查询的性能改进,我们可以生成一组样本数据插入到表1中。下面是一个简单的PHP脚本,它使用长度为2-5、值介于1-100之间的随机向量生成100000行:

<?php
$possible_values = range(1,100);

foreach(range(1,100000) as $id) {
    $vector = array_rand($possible_values, mt_rand(2,5));

    $values = array_map(function($x_id) use ($id) {
        return sprintf("(%d, %d)", $id, $x_id);
    }, $vector);

    echo sprintf("INSERT INTO Table1 (id, x_id) VALUES %s;\n",
        implode(',', $values)
    );
}
让我们比较一下子查询优化的好处,找到一个短向量:

mysql> SELECT SQL_NO_CACHE id, 
    -> SUM(x_id IN (6,25)) AS score,
    -> SUM(1) AS count
    -> FROM Table1
    -> WHERE id IN (
    -> SELECT id FROM Table1 WHERE x_id IN (6,25)
    -> )
    -> GROUP BY id
    -> HAVING score = count AND count = 2;
+-------+-------+-------+
| id    | score | count |
+-------+-------+-------+
| 15265 |     2 |     2 |
| 40816 |     2 |     2 |
| 75000 |     2 |     2 |
| 75239 |     2 |     2 |
| 83498 |     2 |     2 |
+-------+-------+-------+
5 rows in set (0.04 sec)

mysql> SELECT SQL_NO_CACHE id 
    -> FROM table1 
    -> GROUP BY id 
    -> HAVING SUM(x_id IN (6,25)) = COUNT(x_id) 
    -> AND COUNT(*) = 2;
+-------+
| id    |
+-------+
| 15265 |
| 40816 |
| 75000 |
| 75239 |
| 83498 |
+-------+
5 rows in set (0.14 sec)
优化速度加快了100毫秒,占未优化查询时间的29%

你可以通过解释来了解原因

未优化我们正在扫描几乎整个表格:

mysql> explain SELECT SQL_NO_CACHE id  FROM table1  GROUP BY id  HAVING SUM(x_id IN (6,25)) = COUNT(x_id)  AND COUNT(*) = 2 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table1
   partitions: NULL
         type: index
possible_keys: id
          key: id
      key_len: 10
          ref: NULL
         rows: 338846
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)
优化:

mysql> explain SELECT SQL_NO_CACHE id,  SUM(x_id IN (6,25)) AS score, SUM(1) AS count FROM Table1 WHERE id IN ( SELECT id FROM Table1 WHERE x_id IN (6,25) ) GROUP BY id HAVING score = count AND count = 2 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: <subquery2>
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
     filtered: 100.00
        Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: Table1
   partitions: NULL
         type: ref
possible_keys: id
          key: id
      key_len: 5
          ref: <subquery2>.id
         rows: 3
     filtered: 100.00
        Extra: Using index
*************************** 3. row ***************************
           id: 2
  select_type: MATERIALIZED
        table: Table1
   partitions: NULL
         type: range
possible_keys: x_id,id
          key: x_id
      key_len: 5
          ref: NULL
         rows: 6874
     filtered: 100.00
        Extra: Using index condition
3 rows in set, 1 warning (0.00 sec)
在优化过程中,我们可以将聚合的行子集从~338846限制到~6874。MySQL要做的工作要少得多

对于较长的向量(如19,61,62,96),优化的查询运行速度为80ms,而表扫描速度几乎是150ms的两倍


额外的复杂性可能不值得节省100毫秒,但如果Table1有数百万行,与聚合整个表的未优化方法相比,优化查询的性能将变得非常明显。

什么是x_ids值与我的向量完全匹配?请注意,DISTINCT不是一个函数。什么是x_ids值与我的向量完全匹配?请注意DISTINCT不是一个函数。这非常重要比最初接受的答案更干净。我采用了同样的方法,但加入了一个额外的连接
对至少包含一个目标值的行运行聚合函数,这是对大型表的一种有用的优化。对于大多数情况,你的答案可能足够好,而且更容易理解。这比最初接受的答案要清晰得多。我使用了相同的方法,但是使用了一个额外的连接,只对至少包含一个目标值的行运行聚合函数,这是对大型表的一个有用的优化。对于大多数情况,您的操作可能已经足够好了,而且更简单。谢谢!很好地抓住了计数=3。我一定是一路上错误地优化了它。我在我的例子中修正了这一点。但你是对的,搜索向量的子集仍然会以较小的长度匹配。关于性能,我将对其进行测试。这些数字听起来很不寻常。有没有可能你还在使用MySQL 5.5?它的子查询性能非常糟糕。实际上,我测试的版本甚至比这个版本还要旧,所以我很想看看它在您的机器上相对于我的查询的表现。我刚刚对一个有25000个id项的表进行了测试,该表的随机x_id向量长度为2-5,值在1-100之间。我为id添加了一个复合索引x_id。我们的两个查询都在MySQL 5.7.18上以大约60-70毫秒的时间返回。我也不希望看到额外的WHERE子查询步骤得到改进,直到有更多的数据。我经常处理有数百万行的表,所以我总是要做如上所述的额外优化,以避免全表扫描。我认为这一考虑值得作为增编加以注意,但你的答复值得接受。您的查询更干净、更简单,可以一直使用,直到与行计数相关的查询性能成为问题。我在答案中添加了一些比较。谢谢!很好地抓住了计数=3。我一定是一路上错误地优化了它。我在我的例子中修正了这一点。但你是对的,搜索向量的子集仍然会以较小的长度匹配。关于性能,我将对其进行测试。这些数字听起来很不寻常。有没有可能你还在使用MySQL 5.5?它的子查询性能非常糟糕。实际上,我测试的版本甚至比这个版本还要旧,所以我很想看看它在您的机器上相对于我的查询的表现。我刚刚对一个有25000个id项的表进行了测试,该表的随机x_id向量长度为2-5,值在1-100之间。我为id添加了一个复合索引x_id。我们的两个查询都在MySQL 5.7.18上以大约60-70毫秒的时间返回。我也不希望看到额外的WHERE子查询步骤得到改进,直到有更多的数据。我经常处理有数百万行的表,所以我总是要做如上所述的额外优化,以避免全表扫描。我认为这一考虑值得作为增编加以注意,但你的答复值得接受。您的查询更干净、更简单,可以一直使用,直到查询性能相对于行数成为一个问题。