har*_*ash 4 mysql index optimization
我在 MySQL 中有一个名为 的表,messages如下所示:
id (primary key) | description | created_at(timestamp)
Run Code Online (Sandbox Code Playgroud)
该表应该保存我的应用程序用户之间的聊天消息。因此,对它的写操作次数会很高。
该应用程序有一个 API,可返回两个时间戳之间的所有消息。这个查询也很常见,但少于写操作的次数。
我用 100 个并发连接和该表中的大约 15000 行运行 mysqlslap,总时间约为 8.6 秒。
然后我在 上添加了一个二级索引created_at,希望在两次搜索之间在更短的时间内获得结果,但是对于相同的输入,我增加了 0.3 秒。
为什么我没有看到显着的性能提升?
编辑:
这是我的桌子的样子:
DROP TABLE IF EXISTS `mssg`;
CREATE TABLE `mssg` (
`id` INTEGER NULL AUTO_INCREMENT DEFAULT NULL,
`body` MEDIUMTEXT NULL DEFAULT NULL,
`length` VARCHAR NULL DEFAULT NULL,
`created_at` TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
Run Code Online (Sandbox Code Playgroud)
这就是我添加索引的方式:
ALTER TABLE testalter_tbl ADD INDEX (created_at);
Run Code Online (Sandbox Code Playgroud)
通常,select 语句会返回大约 150 到 350 条消息
我将跳过我对CREATE TABLE从错误到侮辱性分类的声明的评论,例如声明所有列NULL(一行的(NULL, NULL, NULL, NULL)含义是什么?)并专注于提出的问题。
8.6 秒和 8.9 秒之间的差异可以忽略不计。据我们所知,这两个测试的运行时间几乎相同。如果您想正确测试,您应该运行更长的测试并使用更大的表(尝试使用 15K、150K、1500K、15M 行),并查看在具有或不具有特定索引之间效率是否发生变化或保持不变。
您还应该检查为 2 种情况下的查询创建的执行计划(在不同的表大小下),看看幕后发生了什么,使用了哪些索引,如果有的话,等等。
我的预测是,随着表变大,索引将变得更有用,因为查询将需要索引查找以查找所需时间范围内的(行 ID),然后从集群 PK 索引中进行一些额外查找(我假设您使用 InnoDB。)
如果没有索引,则每次都必须进行全表扫描。表格越大,您会看到 2 个测试用例(带和不带索引)之间的差异越大。
如果您的绝大多数查询类似于以下内容,则从较小的时间范围内获取行:
SELECT <columns_wanted>
FROM mssg
WHERE created_at >= @start_timestamp
AND created_at < @end_timestamp ;
Run Code Online (Sandbox Code Playgroud)
那么我建议(假设您使用 InnoDB)另一种设计:制作(created_at)表的集群键。由于您可能有 2 行或更多行具有完全相同的时间戳,因此您可以将主键设置为 以(create_at, id)实现此效果(因为 InnoDB 仅允许唯一键用于集群)。您还需要一个额外的指数(id)为AUTO_INCREMENT就可以了。这可以声明UNIQUE或不声明,这是您的选择:
CREATE TABLE mssg (
mssg_id INTEGER NOT NULL AUTO_INCREMENT,
body MEDIUMTEXT NULL,
length VARCHAR(20) NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (created_at, mssg_id),
-- UNIQUE
INDEX mssg_id_ix (mssg_id) -- this is needed for the AutoIncrement
);
Run Code Online (Sandbox Code Playgroud)
这样,您的查询需要的所有行都将存储在集群 (PK) 索引的连续页面中,并且查询的效率 - 只要它们要求的时间范围很小 - 就不会受到桌子。
进一步评论,部分与问题相关;
NULL?我建议您将它们全部更改为NOT NULL除了那些有特定原因允许空值的列。mediumtext要留言?你要存储这么大的消息吗?如果您可以减小尺寸,则性能可能会更好,例如VARCHAR(250).length声明为 asVARCHAR而不是INTEGER?TIMESTAMP列以获取默认值CURRENT_TIMESTAMP(如果应用程序尚未提供该列。)| 归档时间: |
|
| 查看次数: |
529 次 |
| 最近记录: |