mysql 5.7 json 类型 json 数组类型 普通字符串类型 10w数据 查询速度差异

Posted linzm14

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql 5.7 json 类型 json 数组类型 普通字符串类型 10w数据 查询速度差异相关的知识,希望对你有一定的参考价值。

json 非数组

建表语句ddl

CREATE TABLE tb_json_test (
  id INT NOT NULL AUTO_INCREMENT,
  user_no VARCHAR(100),
  user_name VARCHAR(100),
  score INT,
  create_time date,
  update_time date,
  remark VARCHAR(100),
  field1 VARCHAR(100),
  field2 VARCHAR(100),
  field3 VARCHAR(100),
  field4 VARCHAR(100),
  field5 VARCHAR(100),
  field6 VARCHAR(100),
  field7 VARCHAR(100),
  field8 VARCHAR(100),
  json_field json,
  PRIMARY KEY (id)
);

10w 数据 插入 存储过程

create PROCEDURE `demo02`.`jsonQueryTest`()
BEGIN
    DECLARE i INT DEFAULT 1;
    DECLARE j INT DEFAULT 2011;
    DECLARE user_name VARCHAR(20);
    DECLARE user_no VARCHAR(20);
    DECLARE score INT;
    DECLARE create_time DATETIME DEFAULT NOW();
    DECLARE update_time DATETIME;
    DECLARE remark VARCHAR(50);
    declare field1 VARCHAR(100); 
    declare field2 VARCHAR(100); 
    declare field3 VARCHAR(100); 
    declare field4 VARCHAR(100); 
    declare field5 VARCHAR(100); 
    declare field6 VARCHAR(100); 
    declare field7 VARCHAR(100); 
    declare field8 VARCHAR(100); 
    declare id VARCHAR(100); 
    declare json_field json;
        set autocommit=0; -- 关闭自动提交事务,提高插入效率
    
    WHILE i <= 100000 DO
        SET user_name = CONCAT(
            SUBSTRING(\'赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水竺苏潘范雷\', FLOOR(RAND() * 54) + 1, 1),
            SUBSTRING(\'安宝彪彬冰博财成程达德东斗政法菲飞丰歌根光国海恒弘鸿宏洪华晖惠建健金景\', FLOOR(RAND() * 30) + 1, 1),
            SUBSTRING(\'静俊凯克莉良亮林玲龙茂梅民敏明娜宁鹏平奇琪全仁荣瑞森帅顺涛韬\', FLOOR(RAND() * 30) + 1, 1)
        );
        SET user_no = CONCAT(j, LPAD(i, 7, \'0\'));
        SET score = FLOOR(RAND() * 101);
        SET remark = CONCAT(\'remark_\', i);
        SET update_time = DATE_ADD(create_time, INTERVAL FLOOR(RAND() * 100) DAY); -- update_time则随机生成在create_time基础上加上一定天数的时间。
        set field1 = replace(uuid(),"-","");
           set field2 = replace(uuid(),"-","");
        set field3 = replace(uuid(),"-","");
        set field4 = replace(uuid(),"-","");
        set field5 = replace(uuid(),"-",""); 
        set field6 = replace(uuid(),"-","");
        set field7 = replace(uuid(),"-","");
        set field8 = replace(uuid(),"-","");
        set id = i;
        set json_field = JSON_OBJECT(\'user_no\', user_no, \'user_name\', user_name, \'score\', score);
        INSERT INTO demo02.tb_json_test(id, user_no, user_name, score, create_time, update_time, remark, field1, field2, field3, field4, field5, field6, field7, field8, json_field)
        VALUES(id, user_no, user_name, score, create_time, update_time, remark,field1, field2, field3, field4, field5, field6, field7, field8, json_field);
        
                SET create_time = DATE_ADD(create_time, INTERVAL 1 SECOND); -- create_time初始值为当前时间,每生成一行数据就自增1分钟,以保证创建时间的递增。
        SET i = i + 1;
        IF i % 100000 = 0 THEN
            SET j = j + 1;
        END IF;
    END WHILE;
end

call jsonQueryTest();

 json 类型 vs 普通字符串类型

-- json 非数组
-- 40 条记录 无索引 多次查询 400多ms 
select * from tb_json_test where user_name = \'博玲\'
-- 创建 user_name 索引
CREATE INDEX idx_user_name ON tb_json_test(user_name);
-- 40 条记录 有索引 多次查询 3左右ms 
select * from tb_json_test where user_name = \'博玲\'
-- 40 条记录 无索引 json 多次查询 700多ms 
select * from tb_json_test where JSON_CONTAINS(json_field -> \'$.user_name\', \'"博玲"\')
-- json类型 字段 创建虚拟列索引
ALTER TABLE tb_json_test ADD COLUMN v_user_name VARCHAR(255) AS (JSON_EXTRACT(json_field, \'$.user_name\')) VIRTUAL;
CREATE INDEX idx_v_user_name ON tb_json_test(v_user_name);
-- 40 条记录 有索引 多次查询 3左右ms 
select * from tb_json_test where v_user_name = \'"博玲"\'

json 数组

建表语句ddl

CREATE TABLE tb_json_array_test (
id INT NOT NULL AUTO_INCREMENT,
user_no VARCHAR(100),
user_name VARCHAR(100),
score INT,
create_time date,
update_time date,
remark VARCHAR(100),
field1 VARCHAR(100),
field2 VARCHAR(100),
field3 VARCHAR(100),
field4 VARCHAR(100),
field5 VARCHAR(100),
field6 VARCHAR(100),
field7 VARCHAR(100),
field8 VARCHAR(100),
json_field json,
PRIMARY KEY (id)
);

10w 数据 插入 存储过程


create PROCEDURE `demo02`.`jsonArrayQueryTest`()
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE j INT DEFAULT 2011;
DECLARE user_name VARCHAR(20);
DECLARE user_no VARCHAR(20);
DECLARE score INT;
DECLARE create_time DATETIME DEFAULT NOW();
DECLARE update_time DATETIME;
DECLARE remark VARCHAR(50);
declare field1 VARCHAR(100);
declare field2 VARCHAR(100);
declare field3 VARCHAR(100);
declare field4 VARCHAR(100);
declare field5 VARCHAR(100);
declare field6 VARCHAR(100);
declare field7 VARCHAR(100);
declare field8 VARCHAR(100);
declare id VARCHAR(100);
declare json_field json;
set autocommit=0; -- 关闭自动提交事务,提高插入效率

WHILE i <= 100000 DO
SET user_name = CONCAT(
SUBSTRING(\'赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水竺苏潘范雷\', FLOOR(RAND() * 54) + 1, 1),
SUBSTRING(\'安宝彪彬冰博财成程达德东斗政法菲飞丰歌根光国海恒弘鸿宏洪华晖惠建健金景\', FLOOR(RAND() * 30) + 1, 1),
SUBSTRING(\'静俊凯克莉良亮林玲龙茂梅民敏明娜宁鹏平奇琪全仁荣瑞森帅顺涛韬\', FLOOR(RAND() * 30) + 1, 1)
);
SET user_no = CONCAT(j, LPAD(i, 7, \'0\'));
SET score = FLOOR(RAND() * 101);
SET remark = CONCAT(\'remark_\', i);
SET update_time = DATE_ADD(create_time, INTERVAL FLOOR(RAND() * 100) DAY); -- update_time则随机生成在create_time基础上加上一定天数的时间。
set field1 = replace(uuid(),"-","");
set field2 = replace(uuid(),"-","");
set field3 = replace(uuid(),"-","");
set field4 = replace(uuid(),"-","");
set field5 = replace(uuid(),"-","");
set field6 = replace(uuid(),"-","");
set field7 = replace(uuid(),"-","");
set field8 = replace(uuid(),"-","");
set id = i;
set json_field = JSON_ARRAY(JSON_OBJECT(\'user_no\', user_no, \'user_name\', user_name, \'score\', score), JSON_OBJECT(\'user_no\', user_no, \'user_name\', user_name, \'score\', score));
INSERT INTO demo02.tb_json_array_test(id, user_no, user_name, score, create_time, update_time, remark, field1, field2, field3, field4, field5, field6, field7, field8, json_field)
VALUES(id, user_no, user_name, score, create_time, update_time, remark,field1, field2, field3, field4, field5, field6, field7, field8, json_field);

SET create_time = DATE_ADD(create_time, INTERVAL 1 SECOND); -- create_time初始值为当前时间,每生成一行数据就自增1分钟,以保证创建时间的递增。
SET i = i + 1;
IF i % 100000 = 0 THEN
SET j = j + 1;
END IF;
END WHILE;
end

call jsonArrayQueryTest();

 json 类型 vs 普通字符串类型

-- json 数组
call jsonArrayQueryTest();
select * from tb_json_array_test
-- 40 条记录 无索引 多次查询 400多ms
select * from tb_json_array_test where user_name = \'博玲\'
-- 创建 user_name 索引
CREATE INDEX idx_user_name ON tb_json_array_test(user_name);
-- 40 条记录 有索引 多次查询 3左右ms
select * from tb_json_test where user_name = \'博玲\'
-- 40 条记录 无索引 json 数组 多次查询 700多ms
select * from tb_json_test where JSON_CONTAINS(json_field -> \'$[0].user_name\', \'"博玲"\')
-- json 数组 如果里面的对象不同 无法很好地建立虚拟索引

总结

json 类型 创建虚拟索引的查询速度不差于创建索引的普通字符串

创建索引的普通字符串 > 创建虚拟索引 json > 不创建索引的普通字符串 > 不创建虚拟索引 json

从mysql查询php创建数组

【中文标题】从mysql查询php创建数组【英文标题】:create array from mysql query php 【发布时间】:2011-03-25 19:46:57 【问题描述】:

我有一个小问题,我不明白。我有一个拥有所有者和类型的数据库(当然还有更多)。我想获取所有者等于当前用户的所有类型值的列表,但我只得到两个结果

$sql = "SELECT type FROM cars WHERE owner='".mysql_real_escape_string($_SESSION['username'])."' AND selling='0' ORDER BY id DESC "; 

 $result = mysql_query($sql,$con); 

 print_r(mysql_fetch_array($result));

打印出来:

Array ( [0] => 18 [type] => 18 )

$sql = "SELECT type FROM cars WHERE owner='".mysql_real_escape_string($_SESSION['username'])."' AND selling='0' "; 

打印出来:

Array ( [0] => 16 [type] => 16 ) 

结果应该是数组中的 19、19、18、17、16。这就是将我设置为所有者的所有类型。

我现在已经开始工作了:

for ($x = 0; $x < mysql_num_rows($result); $x++)
 $row = mysql_fetch_assoc($result);  
 echo $row['type']; 

这里我正确打印出所有值,但我需要创建一个包含所有值的数组。我虽然可以使用array_push,但大多数情况下都有更好的方法。我想我会用一个简单的 mysql 查询来获得所有类型的值。

【问题讨论】:

【参考方案1】:

您可能想查看 Wikipedia 上的 SQL 注入文章。查看“十六进制转换”部分,找到一个小函数来执行 SQL 命令并返回一个包含信息的数组。

https://en.wikipedia.org/wiki/SQL_injection

我编写了 dosql() 函数,因为我厌倦了让我的 SQL 命令到处执行,忘记检查错误,并且能够将我的所有命令记录到日志文件中,以便以后在需要时查看.该例程对于任何想将其用于任何目的的人都是免费的。实际上,我已经对函数进行了一些扩展,因为我希望它做更多事情,但是这个基本函数是从 SQL 调用中获取输出的一个很好的起点。

【讨论】:

【参考方案2】:
THE CORRECT WAY ************************ THE CORRECT WAY

while($rows[] = mysqli_fetch_assoc($result));
array_pop($rows);  // pop the last row off, which is an empty row

【讨论】:

是的!这是正确的方式。 他没有使用 mysqli 他使用的是旧版 mysql 旧版 mysql?您一定是指已弃用的 Mysql。 是的 旧 mysql - 比答案相关的版本旧【参考方案3】:
$type_array = array();    
while($row = mysql_fetch_assoc($result)) 
    $type_array[] = $row['type'];

【讨论】:

【参考方案4】:

这通常在while 循环中完成:

$types = array();

while(($row =  mysql_fetch_assoc($result))) 
    $types[] = $row['type'];

查看documentation 中的示例。

mysql_fetch_* 方法将始终获取结果集的 next 元素:

返回对应于获取行的字符串数组,如果没有更多行,则返回 FALSE。

这就是while 循环起作用的原因。如果没有任何行,$row 将是 false 并且存在 while 循环。

似乎mysql_fetch_array 得到的结果不止一行,因为默认情况下它得到的结果为normal and as associative value:

通过使用 MYSQL_BOTH(默认),您将获得一个包含关联索引和数字索引的数组。

您的示例显示得最好,您得到相同的值18,您可以通过$v[0]$v['type'] 访问它。

【讨论】:

【参考方案5】:

您还可以使用包装器让生活更轻松,例如使用 ADODb:

$myarray=$db->GetCol("SELECT type FROM cars ".
    "WHERE owner=? and selling=0", 
    array($_SESSION['username']));

一个好的包装器也会为你做所有的转义,让事情更容易阅读。

【讨论】:

【参考方案6】:
while($row = mysql_fetch_assoc($result)) 
  echo $row['type'];

【讨论】:

他的代码已经在这样做了。他希望它变成一个数组。回声并不能解决这个问题。【参考方案7】:

您确实需要遍历...

$typeArray = array();
$query = "select * from whatever";
$result = mysql_query($query);

if ($result) 
    while ($record = mysql_fetch_array($results)) $typeArray[] = $record['type'];

【讨论】:

以上是关于mysql 5.7 json 类型 json 数组类型 普通字符串类型 10w数据 查询速度差异的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 5.7新支持--------Json类型实战

在 MySQL 5.7 中弹出 JSON 数组中的最后一项

MySQL 5.7 JSON 数据类型可以容纳多少

如何在 MySQL 5.7 中的 JSON 数组中获取唯一/不同的元素

mysql 5.7 json类型字段操作

Mysql 5.7 json 数据类型,在 Rails 5 中使用 activerecord 查询