【问题标题】:Why postgresql's single insert statement is faster than mysql?为什么postgresql的单条insert语句比mysql快?
【发布时间】:2014-03-15 12:10:38
【问题描述】:

我想知道为什么 postgresql 的单个“插入”语句在打开自动提交时完全比 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` datetime NOT NULL,
  `mobile_phone` char(11) NOT NULL,
  `is_admin` enum('yes','no') NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

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")
) ;

商店功能:

MySQL:

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  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;

参数:

MySQL:
innodb_buffer_pool_size=32M
bulk_insert_buffer_size=20M
autocommit=on
PostgreSQL:
shared_memory=32M
effective_cache_size=20M
autocommit=on

测试结果: MySQL:

mysql> call sp_insert_user_simple(10000);
Query OK, 1 row affected (1 min 9.93 sec)

PostgreSQL:

ytt=# select sp_insert_user_simple(10000); 
 sp_insert_user_simple 
-----------------------

(1 row)

Time: 1177.043 ms

上面的测试表明MySQL的运行时间是69.93秒,而PostgreSQL只有1.17秒。
任何答案表示赞赏。谢谢。

【问题讨论】:

  • 不相关,但是: (a) 您可以在 MySQL 中打开 ANSI 模式,然后使用合理的引用; (b) 不要使用char 类型,使用varcharchar 太糟糕了。此外,这两个过程都是不必要的,您应该能够将它们编写为单个 insert 语句而无需过程。无论如何:我想知道 MySQL 的自动提交是否在过程中单独提交每个插入(我没有使用 MySQL 的过程)。 PostgreSQL 没有,它最后对整个函数进行了一次提交。这很容易解释差异。
  • 谢谢,我明白了。我将尝试使用应用程序语言重写测试代码。

标签: mysql postgresql


【解决方案1】:

我认为这里发生的事情是 MySQL 的程序可能正在为每个人 INSERT 进行提交。在 PostgreSQL 中,整个过程在最后提交;程序不能运行单个事务。 (我不完全确定 MySQL 的过程在 autocommit=off 时的行为是否如此,但似乎是从快速查看文档中得出的)。

无论如何,您确实应该将 INSERT 作为单个语句执行,使用 INSERT ... SELECT

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,而不是varcharchar 是一种糟糕的数据类型,应该避免使用。此外,请考虑将boolean 用于is_admin 列。

【讨论】:

  • char 在 MySQL 中并没有那么糟糕。
  • 感谢您的回复。我现在了解了 postgresql 的特殊自动提交功能。
【解决方案2】:

尝试测试简单的插入查询:

INSERT INTO ytt.user (username, password) VALUES ('a', 'b');

并在一个过程中循环它,从而使时间测量更准确。避免使用其他内置函数(如 rngtimestamp),因为它们的性能在大样本上可能会有显着差异,当然,除非你先测试了它们。

【讨论】:

    猜你喜欢
    • 2011-10-26
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 2013-07-20
    • 2011-12-04
    • 2013-11-13
    • 2013-11-09
    • 2013-12-02
    相关资源
    最近更新 更多