加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

MySQL:强制查询在WHERE子句中使用带有局部变量的索引

发布时间:2021-03-05 18:35:06 所属栏目:MySql教程 来源:网络整理
导读:上下文 我有一个应用程序从表中选择加权随机条目,其中前缀总和(权重)是关键部分.简化的表定义如下所示: CREATE TABLE entries ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,weight DECIMAL(9,3),fenwick DECIMAL(9,3)) ENGINE=MEMORY; 其中`fenwick`将值

mysql> select sum(fenwick) from entries where id in (32,60);
+--------------+
| sum(fenwick) |
+--------------+
|       32.434 |
+--------------+
1 row in set (0.00 sec)

验证

mysql> select sum(weight) from entries where id <= @entryid;
+-------------+
| sum(weight) |
+-------------+
|      32.434 |
+-------------+
1 row in set (0.00 sec)

现在,让我们比较这些查询的效率.

mysql> explain select sum(fenwick) from entries where id in (32,60);
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | entries | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    4 |   100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

或者,有所不同

explain format=json select sum(fenwick) from entries where id in (32,60);
{
  "query_block": {
    "select_id": 1,"cost_info": {
      "query_cost": "5.61"
    },"table": {
      "table_name": "entries","access_type": "range","possible_keys": [
        "PRIMARY"
      ],"key": "PRIMARY","used_key_parts": [
        "id"
      ],"key_length": "4","rows_examined_per_scan": 4,"rows_produced_per_join": 4,"filtered": "100.00","cost_info": {
        "read_cost": "4.81","eval_cost": "0.80","prefix_cost": "5.61","data_read_per_join": "64"
      },"used_columns": [
        "id","fenwick"
      ],"attached_condition": "(`test`.`entries`.`id` in (32,60))"
    }
  }

因此,优化器通过主键获取4行(IN子句中有4个值).

当不使用fenwick索引时,我们有

mysql> explain select sum(weight) from entries where id <= @entryid;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | entries | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |   60 |   100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

或者,表达方式不同

explain format=json select sum(weight) from entries where id <= @entryid;
{
  "query_block": {
    "select_id": 1,"cost_info": {
      "query_cost": "25.07"
    },"rows_examined_per_scan": 60,"rows_produced_per_join": 60,"cost_info": {
        "read_cost": "13.07","eval_cost": "12.00","prefix_cost": "25.07","data_read_per_join": "960"
      },"weight"
      ],"attached_condition": "(`test`.`entries`.`id` <= (@`entryid`))"
    }
  }

优化器在此执行索引扫描,读取60行.

ID = 60时,fenwick的好处是4次,而60次.

现在,考虑一下如何扩展,例如值高达64K.

对于fenwick,16位值将设置最多16位,因此要查找的元素数量最多为16.

如果没有fenwick,扫描最多可以读取64K条目(平均读数为32K).

问题2,找到给定重量的条目

OP问题是找到给定重量的条目.

例如

SET @search_weight := 35.123;

为了说明算法,这篇文章详细说明了如何完成查找(对不起,如果这太冗长了)

SET @found_id := 0;

首先,找出有多少条目.

SET @max_id := (select id from entries order by id desc limit 1);

在测试数据中,max_id为156.

因为128< = max_id< 256,开始搜索的最高位是128.

mysql> set @search_id := @found_id + 128;
mysql> select id,fenwick,@search_weight,->    if (fenwick <= @search_weight,"keep","discard") as action
    ->    from entries where id = @search_id;
+-----+---------+----------------+---------+
| id  | fenwick | @search_weight | action  |
+-----+---------+----------------+---------+
| 128 |  66.540 |         35.123 | discard |
+-----+---------+----------------+---------+

重量66.540大于我们的搜索,因此丢弃128,继续下一位.

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读