为什么是postgresql';s的单insert语句比mysql快?
我想知道为什么postgresql的单个“insert”语句在启用autocommit时比MySQL的语句要快得多?下面的代码与我对它们所做的代码相同 版本:为什么是postgresql';s的单insert语句比mysql快?,mysql,postgresql,Mysql,Postgresql,我想知道为什么postgresql的单个“insert”语句在启用autocommit时比MySQL的语句要快得多?下面的代码与我对它们所做的代码相同 版本: MySQL: 5.6.10 PostgreSQL: PostgreSQL 9.3.2 on x86_64 表定义: MySQL: CREATE TABLE `user` ( `username` char(36) NOT NULL, `password` char(32) NOT NULL, `register_time
MySQL: 5.6.10
PostgreSQL: PostgreSQL 9.3.2 on x86_64
表定义:
MySQL:
CREATE TABLE `user` (
`username` char(36) NOT NULL,
`password` char(32) NOT NULL,
`register_time` datetime NOT NULL,
`mobile_phone` char(11) NOT NULL,
`is_admin` enum('yes','no') NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
DELIMITER $$
USE `t_girl`$$
DROP PROCEDURE IF EXISTS `sp_insert_user_simple`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_insert_user_simple`(
IN f_input INT
)
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i <= f_input
DO
INSERT INTO t_girl.user (`username`, `password`, register_time,mobile_phone,is_admin)
VALUES (UUID(),MD5(REPLACE(UUID(),'-','')),DATE_SUB(NOW(),INTERVAL CEIL(RAND()*40) DAY),CEIL(RAND()*10000)+13800000000,IF(TRUNCATE(RAND()*2,0)=1,'yes','no'));
SET i = i + 1;
END WHILE;
END$$
DELIMITER ;
PostgreSQL:
CREATE TYPE ytt_enum AS ENUM ('yes','no');
CREATE TABLE ytt."user" (
"username" char(36) NOT NULL,
"password" char(32) NOT NULL,
"register_time" timestamp NOT NULL,
"mobile_phone" char(11) NOT NULL,
"is_admin" ytt_enum NOT NULL,
PRIMARY KEY ("username")
) ;
CREATE or replace function sp_insert_user_simple(
IN f_input INT
) returns void as
$ytt$
declare i int := 0;
v_username char(36);
v_password char(32);
v_register_time timestamp;
v_mobile_phone char(11);
v_is_admin ytt_enum;
BEGIN
WHILE i < f_input
loop
v_username := uuid_generate_v1();
v_password :=MD5(REPLACE(uuid_generate_v1()::text,'-',''));
v_register_time := to_timestamp((now() - '1 day'::interval*ceil(random()*40))::text,'yyyy-mm-dd HH24:MI:SS');
v_mobile_phone :=CEIL(RANDOM()*10000)+13800000000;
v_is_admin := (case TRUNC(RANDOM()*2) when 1 then 'yes' else'no' end)::ytt_enum;
INSERT INTO ytt.user (username, password, register_time,mobile_phone,is_admin)
VALUES (v_username,v_password,v_register_time,v_mobile_phone,v_is_admin);
i := i + 1;
END loop;
END;
$ytt$language plpgsql;
ytt=# select sp_insert_user_simple(10000);
sp_insert_user_simple
-----------------------
(1 row)
Time: 1177.043 ms
存储功能:
MySQL:
CREATE TABLE `user` (
`username` char(36) NOT NULL,
`password` char(32) NOT NULL,
`register_time` datetime NOT NULL,
`mobile_phone` char(11) NOT NULL,
`is_admin` enum('yes','no') NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
DELIMITER $$
USE `t_girl`$$
DROP PROCEDURE IF EXISTS `sp_insert_user_simple`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_insert_user_simple`(
IN f_input INT
)
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i <= f_input
DO
INSERT INTO t_girl.user (`username`, `password`, register_time,mobile_phone,is_admin)
VALUES (UUID(),MD5(REPLACE(UUID(),'-','')),DATE_SUB(NOW(),INTERVAL CEIL(RAND()*40) DAY),CEIL(RAND()*10000)+13800000000,IF(TRUNCATE(RAND()*2,0)=1,'yes','no'));
SET i = i + 1;
END WHILE;
END$$
DELIMITER ;
测试结果:
MySQL:
PostgreSQL:
CREATE TYPE ytt_enum AS ENUM ('yes','no');
CREATE TABLE ytt."user" (
"username" char(36) NOT NULL,
"password" char(32) NOT NULL,
"register_time" timestamp NOT NULL,
"mobile_phone" char(11) NOT NULL,
"is_admin" ytt_enum NOT NULL,
PRIMARY KEY ("username")
) ;
CREATE or replace function sp_insert_user_simple(
IN f_input INT
) returns void as
$ytt$
declare i int := 0;
v_username char(36);
v_password char(32);
v_register_time timestamp;
v_mobile_phone char(11);
v_is_admin ytt_enum;
BEGIN
WHILE i < f_input
loop
v_username := uuid_generate_v1();
v_password :=MD5(REPLACE(uuid_generate_v1()::text,'-',''));
v_register_time := to_timestamp((now() - '1 day'::interval*ceil(random()*40))::text,'yyyy-mm-dd HH24:MI:SS');
v_mobile_phone :=CEIL(RANDOM()*10000)+13800000000;
v_is_admin := (case TRUNC(RANDOM()*2) when 1 then 'yes' else'no' end)::ytt_enum;
INSERT INTO ytt.user (username, password, register_time,mobile_phone,is_admin)
VALUES (v_username,v_password,v_register_time,v_mobile_phone,v_is_admin);
i := i + 1;
END loop;
END;
$ytt$language plpgsql;
ytt=# select sp_insert_user_simple(10000);
sp_insert_user_simple
-----------------------
(1 row)
Time: 1177.043 ms
上面的测试显示MySQL的运行时间是69.93秒,而PostgreSQL的运行时间只有1.17秒。任何答复都将不胜感激。谢谢。我认为这里发生的事情是MySQL的过程可能正在为每个
插入的进行提交。在PostgreSQL中,整个过程在最后提交;过程不能运行单个事务。(我不完全确定在autocommit=off的情况下,MySQL的过程是否就是这样运行的,但通过快速查看文档可以看出这一点)
无论如何,您都应该使用INSERT,INSERT作为单个语句来执行此操作。。。选择
:
CREATE or replace function sp_insert_user_simple(
IN f_input integer
) returns void AS $$
INSERT INTO ytt.user (username, password, register_time,mobile_phone,is_admin)
SELECT
uuid_generate_v1(),
MD5(REPLACE(uuid_generate_v1()::text,'-','')),
to_timestamp((now() - '1 day'::interval*ceil(random()*40))::text,'yyyy-mm-dd HH24:MI:SS'),
CEIL(RANDOM()*10000)+13800000000,
case TRUNC(RANDOM()*2) when 1 then 'yes' else'no' end
FROM generate_series(1,$1);
$$ LANGUAGE sql;
(我假设这是虚拟用户数据生成?)
另外,请使用char
,不要使用varchar
char
是一种糟糕的数据类型,应该避免使用。此外,考虑使用<代码>布尔< <代码> > <代码> iSuthAdmin 列。尝试测试简单插入查询:
INSERT INTO ytt.user (username, password) VALUES ('a', 'b');
并在程序中循环,从而使时间测量更准确。避免使用其他内置函数(如rng和timestamp),因为它们的性能在大样本上可能会有很大差异,当然,除非您首先测试了这些函数。不相关,但是:(a)您可以在MySQL中打开ANSI模式,然后使用合理的引用;(b)不要使用char
类型,使用varchar
<代码>字符
很糟糕。此外,这两个过程都是不必要的,您应该能够将它们编写为单个insert
语句,而不需要过程。无论如何:我想知道MySQL的autocommit是否在过程中单独提交每个插入(我没有使用MySQL的过程)。PostgreSQL没有,它在最后对整个函数执行一次提交。这很容易解释区别。谢谢,我明白了。我将尝试使用应用程序语言重写测试代码。char
没有那么糟糕-在MySQL中。谢谢您的回复。我现在了解了postgresql的特殊自动提交功能。