一千万数据,怎么快速查询

【一千万数据,怎么快速查询】
CREATE TABLE user_operation_log (
id int(11) NOT NULL AUTO_INCREMENT,
user_id varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
ip varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
op_data varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr2 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr3 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr4 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr5 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr6 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr7 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr8 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr9 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr10 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr11 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
attr12 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

创建数据脚本
采用批量插入,效率会快很多,而且每1000条数就commit,数据量太大,也会导致批量插入效率慢

DELIMITER ;;
CREATE PROCEDURE batch_insert_log()
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE userId INT DEFAULT 10000000;
set @execSql = ‘INSERT INTO test.user_operation_log(user_id, ip, op_data, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9, attr10, attr11, attr12) VALUES’;
set @execData = ‘’;
WHILE i<=10000000 DO
set @attr = “‘测试很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的属性’”;
set @execData = concat(@execData, “(”, userId + i, “, ‘10.0.69.175’, ‘用户登录操作’”, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “,”, @attr, “)”);
if i % 1000 = 0
then
set @stmtSql = concat(@execSql, @execData,“;”);
prepare stmt from @stmtSql;
execute stmt;
DEALLOCATE prepare stmt;
commit;
set @execData = “”;
else
set @execData = concat(@execData, “,”);
end if;
SET i=i+1;
END WHILE;

END;;
DELIMITER ;

不同数据量,相同偏移量:数据量越大,耗时越大
相同数据量,不同偏移量:偏移量越大,耗时越大

【优化方式一:子查询】

先定位偏移位置的id,然后再查询对应页的数据
SELECT * FROM user_operation_log LIMIT 1000000, 10 //
SELECT id FROM user_operation_log LIMIT 1000000, 1 // 有索引的情况下,耗时很小
SELECT * FROM user_operation_log WHERE id >= (SELECT id FROM user_operation_log LIMIT 1000000, 1) LIMIT 10

查询结果如下:
第一条:4818ms
第二条:4312ms/199ms
第三条:4319/201ms

第一条花费的时间最大,第三条比第一条稍微好点,子查询使用索引速度更快
缺点:只适用于id递增的情况

id非递增的情况可使用如下写法:

SELECT * FROM user_operation_log WHERE id IN (SELECT t.id FROM (SELECT id FROM user_operation_log LIMIT 1000000, 10) AS t)
缺点:分页查询只能放在子查询里面
注意:某些 mysql 版本不支持在 in 中使用 limit,所以采用了多个嵌套select

【优化方式二:id范围限定】

id必须是连续递增,先计算id的范围,再使用 between:
SELECT * FROM user_operation_log WHERE id between 1000000 AND 1000100 LIMIT 100
SELECT * FROM user_operation_log WHERE id >= 1000000 LIMIT 100
注意:这里的 LIMIT 限制条数,没有采用偏移量。

【优化数据量大的问题】

返回结果的数据量也会直接影响速度
SELECT * FROM user_operation_log LIMIT 1, 1000000
SELECT id FROM user_operation_log LIMIT 1, 1000000
SELECT id, user_id, ip, op_data, attr1, attr2, attr3, attr4, attr5, attr6, attr7, attr8, attr9, attr10, attr11, attr12 FROM user_operation_log LIMIT 1, 1000000

减少不需要的列,查询效率也可以得到明显提升。

【不用select
(1)用 "SELECT * " 数据库需要解析更多的对象、字段、权限、属性等相关内容。
在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
(2)增大网络开销,
有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增涨。
特别是MySQL和应用程序不在同一台机器,这种开销非常明显。

【一千万的数据如何高效查?】

不能这么搞,直接拒绝回答

【数据库中如何优雅地存储ip地址】

IPv4地址是一个4字节的无符号整数。
IPv4通常被写作点分十进制的形式。

使用varchar要使用3*4+3+1=16B(varchar的长度<=255时,需要1B保存长度)
使用int是4B

《高性能MySql》建议:
在够用的前提下,字节能省则省。所以用无符号的int(10)存储IPv4是最好的选择。

CREATE TABLE login_log (
id int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT ‘主键id’,
user_id bigint(20) NOT NULL COMMENT ‘用户id’,
ipv4 int(10) unsigned DEFAULT NULL COMMENT ‘ipv4地址 int类型’,
ipv4_string varchar(16) DEFAULT NULL COMMENT ‘ipv4地址 varchar类型’,
ip varbinary(16) DEFAULT NULL COMMENT ‘ip地址,兼容ipv4和ipv6’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO login_log(user_id, ipv4, ipv4_string) VALUES(1, INET_ATON(“192.168.1.5”), “192.168.1.5”);
SELECT *, INET_NTOA(ipv4) FROM login_log

INET_ATON() 将IPv4的字符串地址转换成数值,
INET_NTOA() 将IPv4的数值转换成字符串地址。

IPv6是一个16字节的整数。
MySQL不支持16字节的整数(最大为8字节的bigint类型),所以无法使用整数存储IPv6。
先看看IPv6的三种常见的表示方式:

(1)冒分十六进制表示法
格式为X:X:X:X:X:X:X:X,其中每个X表示地址中的16b(2B)。
以十六进制表示,ABCD:EF01:2345:6789:ABCD:EF01:2345:6789。
每个X的前导0可省略,例如:
2001:0DB8:0000:0023:0008:0800:200C:417A→2001:DB8:0:23:8:800:200C:417A

(2)0位压缩表示法
IPv6地址中间可能包含很长的一段0,可以把连续的一段0压缩为“::”。
但为保证地址解析的唯一性,地址中”::”只能出现一次。
例如:
FF01:0:0:0:0:0:0:1101 → FF01::1101
0:0:0:0:0:0:0:1 → ::1
0:0:0:0:0:0:0:0 → ::

(3)内嵌IPv4地址表示法
为了实现IPv4-IPv6互通,IPv4地址会嵌入IPv6地址中。
地址常表示为:X:X:X:X:X:X:d.d.d.d。
前96b采用冒分十六进制表示,后32b地址使用IPv4点分十进制表示。
例如
::192.168.0.1
::FFFF:192.168.0.1
(在前96b中,压缩0位的方法依旧适用)
如果使用varchar类型保存IPv6,那么存储以冒分十六进制表示的IPv6时,需要39 + 1 = 40 B。
IPv6本质上一个16字节的数字。

在《高性能MySQL 第三版》中有句话:
与CHAR和VARCHAR类似的类型还有BINARY和VARBINARY,它们存储的是二进制字符串。
二进制字符串和常规字符串非常相似,但是二进制字符串存储的是字节码而不是字符。
同时,要注意到VARBINARY(m),其中m表示字节数。
这样可以使用VARBINARY(16)存储IPv6地址,并且兼容存储IPv4地址。

对三种不同方式表示IPv6地址的记录进行插入:
INSERT INTO login_log(user_id, times, ip) VALUES(1, 2, inet6_aton(“2001:db8:85a3:8d3:1319:8a2e:370:7348”));
INSERT INTO login_log(user_id, times, ip) VALUES(1, 3, inet6_aton(“fe80::3579:5807:93af:a2ce”));
INSERT INTO login_log(user_id, times, ip) VALUES(1, 4, inet6_aton(“::192.168.0.1”));
SELECT *, INET6_NTOA(ip) FROM login_log

INET6_ATON() 将IPv6的字符串地址转换成数值
INET6_NTOA() 将IPv6的数值转换成字符串地址

### 回答1: 可以使用以下语句快速删除MySQL数据库中的一千万数据: DELETE FROM table_name LIMIT 10000000; 请确保在运行此语句之前备份数据。此外,由于该操作可能需要一些时间才能成,请在终端或命令提示符窗口中运行此语句,以便在操作成后获得提示。 ### 回答2: 要快速删除一千万数据,可以采取以下方法: 1. 使用TRUNCATE TABLE命令:相对于使用DELETE语句逐行删除数据,TRUNCATE TABLE命令可以更快地删除整个表的数据。它直接释放表所占用的磁盘空间,而不是逐行删除数据,从而提高删除速度。 2. 关闭MySQL的主键和外键检查:在删除大量数据时,关闭主键和外键检查可以显著提高删除速度。可以使用以下语句暂时关闭主键和外键检查: ALTER TABLE table_name DISABLE KEYS; SET FOREIGN_KEY_CHECKS = 0; 删除成后,记得重新启用主键和外键检查: ALTER TABLE table_name ENABLE KEYS; SET FOREIGN_KEY_CHECKS = 1; 3. 优化删除语句:使用DELETE语句删除数据时,可以通过以下优化来提高删除速度: - 使用带索引的WHERE子句:在DELETE语句中,使用带索引的WHERE子句可以加速数据查找和删除。 - 使用LIMIT子句:使用LIMIT子句将删除操作分为多个批次进行,每个批次删除一定数量的数据,避免一次性删除过多数据导致性能下降。 - 使用条件限制范围:根据数据的特点,可以先使用SELECT语句查询出需要删除的数据的范围,然后在DELETE语句中使用这个范围作为条件进行删除。 4. 使用分区表:如果数据表较大且已分区,可以通过删除整个分区来快速删除数据。这种方法可以避免一行一行删除数据的开销。 以上是一些常用的方法来快速删除大量数据,具体的选择和实施方法可以根据实际情况来决定。 ### 回答3: 要快速删除MySQL中的一千万数据,可以采取以下方法: 1. 使用TRUNCATE命令:TRUNCATE是一种快速删除数据的方法,它不仅删除数据,还重置表的自增计数。在执行之前,确保已将表和数据备份。使用以下SQL语句:TRUNCATE TABLE 表名; 2. 使用DELETE命令:DELETE命令将逐行删除指定条件的数据,但相比TRUNCATE,删除速度较慢。为了提高效率,可以按照合适的条件选择删除的范围,避免全表扫描。使用以下SQL语句:DELETE FROM 表名 WHERE 条件; 3. 分批次删除:将一千万数据分为多个子集,并通过循环的方式逐个删除子集,以减轻数据库的负担。例如,可以通过使用LIMIT和OFFSET来限制每次删除的数据量,如:DELETE FROM 表名 WHERE 条件 LIMIT 每次删除的数量 OFFSET 每次删除的偏移量; 4. 使用索引:在数据量庞大的情况下,建立合适的索引可以极大提高数据的删除效率。通过创建适当的索引,可以快速定位要删除的数据行,避免全表扫描的开销。 5. 禁用或简化触发器和约束:在删除大量数据时,禁用触发器和约束可以提高删除的速度。触发器和约束的验证和处理可能会增加删除操作的时间,因此在删除操作之前可以考虑临时禁用它们。 在实施删除操作之前,务必要先备份数据,以防止误删除或数据丢失。此外,在高峰期避免执行删除操作,以免影响其他用户的正常访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值