小表

时间:2016-05-13 04:08:22

标签: mysql sql performance sqlite

我最近迁移到我的PHP会话的数据库存储。在创建了会话处理函数之后,我意识到我的写入速度很慢。

以下查询在MySQL上花费0.04秒,在SQLite上花费0.08秒。这似乎并不慢,直到我意识到该表在新设置中只有6行。

UPDATE sm_sessions
    SET last_access =  '1463104877'
    WHERE session_id = 'smsess-5734112c09619927459593e9866792515f74ba3115d3a1093b3a31018'
    LIMIT 1

而且,这是表结构。

CREATE TABLE IF NOT EXISTS `sm_sessions` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `session_id` char(64) COLLATE utf8mb4_unicode_ci NOT NULL,
  `session_data` text COLLATE utf8mb4_unicode_ci,
  `last_access` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `session_id` (`session_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=57 ;

请注意,我已尝试过所有内容,包括以下内容:

  • 添加了主键并自动增加“id”(此字段在开头不存在,尝试添加它以查看它是否会影响性能)
  • 在session_id上尝试了主键,唯一索引和常规索引
  • 尝试删除所有索引
  • 尝试使用where子句中的id而不是64个字符session_id修改查询以进行更新(无改进)
  • 尝试使用REPLACE INTO和ON DUPLICATE KEY更新(更糟)
  • 直接从mysql cli和phpmyadmin(以及sqlite cli和sqliteadmin)查询 - 相同的性能,所以我知道它不是php或pdo减慢它

据我所知,0.04秒并不是那么糟糕。但是,读取在0.0006秒左右完成。如果我有10次写入是0.4秒。并且,是的,我知道读取通常总是比写入更快,但对于具有6行的表,新设置和如此简单的查询,0.04或更差听起来非常糟糕。

我觉得这个更新查询应该在WORST时需要0.01s,通常在0.005s的范围内。这是一个合理的期望吗?

这是在本地完成的,但即使在不同的服务器上,写入也会相对较慢,因为其他一切都很快。我可以发布代码或mysql / sqlite设置,但我觉得这对于最近制作的6行表格无关紧要。

怎么了?

EDIT |更新安装mysql时创建的mysql表,一个简单的更新查询需要0.005秒。相同数据库服务器出了点问题。

EDIT2 |将存储引擎从InnoDB更改为MyISAM使查询运行得更快 - 0.0009秒。我会将此标记为已解决,我可能会这样做,但有谁知道为什么会加速它?

EDIT3 |对于所有的编辑都很抱歉,但是任何读者都应该知道我在下面的答案中找到了解决方案。

3 个答案:

答案 0 :(得分:2)

由于@ tadman的建议,我开始使用mysqlslab进行基准测试,并且我已经找到了问题。

我的连接和服务器字符集和排序规则设置为latin1和utf8的混合。

此表使用utf8mb4和utf8mb4_general_ci比较字符串。

更改连接和服务器以匹配后,我得到的速度<0.001秒(比之前的0.04秒快40倍)。

展示我的考试..

之前我发现了问题,我运行了以下命令:

scott@scottsdevbox:/etc/mysql$ /usr/bin/mysqlslap --user=root --password=mypasswordhere --delimiter=";" --create="CREATE TABLE a (session_id char(64) COLLATE utf8mb4_unicode_ci NOT NULL, session_data text COLLATE utf8mb4_unicode_ci, last_access int(10) NOT NULL, PRIMARY KEY (session_id)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO  a (session_id ,session_data ,last_access)VALUES ('smsess-57356c97a576f244771728b1cf2b22c3d05ee2a891ab34c4c60cd5fe9',  'abczyx123string',  '1463120872');" --query="UPDATE a SET last_access =  '1463120866' WHERE session_id = 'smsess-57356c97a576f244771728b1cf2b22c3d05ee2a891ab34c4c60cd5fe9' LIMIT 1" --concurrency=1 --iterations=100 --engine="InnoDB"

以0.04的速度获得了通常的结果:

Benchmark
    Running for engine InnoDB
    Average number of seconds to run all queries: 0.046 seconds
    Minimum number of seconds to run all queries: 0.033 seconds
    Maximum number of seconds to run all queries: 0.211 seconds
    Number of clients running queries: 1
    Average number of queries per client: 1

然后,在更改我的服务器和客户端字符集(到utf8mb4)和排序规则(到utf8mb4_general_ci)以匹配数据库和字段之后..

命令:

scott@scottsdevbox:/etc/mysql$ /usr/bin/mysqlslap --user=root --password=mypasswordhere --delimiter=";" --create="CREATE TABLE a (session_id char(64) character set utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, session_data text character set utf8mb4 COLLATE utf8mb4_general_ci, last_access int(10) NOT NULL, PRIMARY KEY (session_id))  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; INSERT INTO  a (session_id ,session_data ,last_access)VALUES ('smsess-57356c97a576f244771728b1cf2b22c3d05ee2a891ab34c4c60cd5fe9',  'abczyx123string',  '1463120872');" --query="UPDATE a SET last_access =  '1463120866' WHERE session_id = 'smsess-57356c97a576f244771728b1cf2b22c3d05ee2a891ab34c4c60cdsed5fe9' LIMIT 1" --concurrency=1 --iterations=100 --engine="InnoDB"

结果:

Benchmark
    Running for engine InnoDB
    Average number of seconds to run all queries: 0.000 seconds
    Minimum number of seconds to run all queries: 0.000 seconds
    Maximum number of seconds to run all queries: 0.001 seconds
    Number of clients running queries: 1
    Average number of queries per client: 1

总之,我了解到更改您的客户端和服务器字符集和排序规则以匹配数据库和表格和字段字符集和排序规则会提高查询速度

答案 1 :(得分:0)

对数据库的每次更改都涉及锁定和同步开销,每个事务只发生一次,并且不依赖于访问或写入的数据量。

因此,当DB的大小增加时,时间可能不会变得更大。

要更快地进行多次写入,请将它们全部放入同一事务中。

答案 2 :(得分:0)

char(64) COLLATE utf8mb4_unicode_ci对于ascii字符串非常糟糕。

  • CHAR是固定宽度,浪费空间。特别是,无论内容如何,​​都需要4 * 64(= 256)个字节。

  • 如果文字总是字母,短划线和数字,则
  • COLLATE utf8mb4_unicode_ci会增加不必要的复杂性。

切换到VARCHAR(64) CHARACTER SET ascii。如果合适,session_data可以保留utf8mb4。