mysql select*by index非常慢

xj3cbfub  于 2021-06-18  发布在  Mysql
关注(0)|答案(3)|浏览(362)

我有一张这样的table:

create table test (
    id int primary key auto_increment,
    idcard varchar(30),
    name varchar(30),
    custom_value varchar(50),
    index i1(idcard)
)

我在表中插入30000000行
然后我执行:

select * from test where idcard='?'

返回语句需要12秒
当我使用iostat监视磁盘时
读取速度约为6 mb/s,而利用率为94%
有什么方法可以优化它吗?

s8vozzvw

s8vozzvw1#

您可以尝试将select子句中的其他三列添加到索引中:

CREATE INDEX idx ON test (idcard, id, name, custom_value);

除了 idcard 正在添加以允许索引覆盖所选的所有内容。当前索引的问题是它只在 idcard . 这意味着一旦mysql向下遍历到索引中的每个叶节点,它就必须对聚集索引执行另一次查找,以查找索引中提到的所有列的值 select * . 因此,mysql可能会选择完全忽略索引。我上面提出的建议避免了这种额外的寻求。

kknvjkwl

kknvjkwl2#

12秒可能是现实的。
关于问题的假设:
总共有3000万行,但结果集中只有3000行。
内存中没有足够的空间来缓存东西,或者您是从一个冷启动运行。
innodb或myisam(分析相同;细节完全不同)。
任何 CHARACTER SET 以及 COLLATION 为了 idcard . INDEX(idcard) 存在并在查询中使用。
hdd磁盘驱动器,而不是ssd。
以下是处理过程的细目:
转到索引,用 ? ,向前扫描,直到找到一个不是 ? (大约3k行之后)。
对于这3k项中的每一项,深入表中查找所有列(cf SELECT * .
把它们送过去。
第一步:快速。
步骤2:这是(基于不被缓存的假设)代价高昂的。它可能涉及大约3k个磁盘点击。对于hdd来说,这大约需要30秒。所以,12秒可能意味着一些东西被缓存了,或者碰巧在彼此附近。
第三步:这是一个网络成本,我没有考虑。
再次运行查询。这次可能只需要1秒——因为所有3k块都缓存在ram中!iostat将显示零活动!
有什么方法可以优化它吗?
好。。。
你已经有了最好的索引。
你打算一次用3000排干什么?这是一次性任务吗?
使用innodb时, innodb_buffer_pool_size 应该是可用ram的70%左右,但不会太大导致交换。它的设置是什么?你有多少内存?机器上还运行什么?
在获取3k行时,您能完成更多的任务吗?
切换到固态硬盘会有所帮助,但我不喜欢硬件绷带;它们不可重复使用。
表有多大(gb)--可能是3gb数据加索引( SHOW TABLE STATUS )如果不能使缓冲池足够大,并且有各种各样的查询竞争这个(和其他)表的不同部分,那么更多的ram可能是有益的。

okxuctiv

okxuctiv3#

似乎更像是i/o限制,而不是可以通过添加索引来解决的问题。提高速度的方法是将idcard列的排序规则改为latin1\u bin。每个字符仅使用1字节。它还使用二进制比较,这比不区分大小写的比较快。
只有在idcard列中没有特殊字符时才这样做,因为拉丁1的字符集非常有限。

ALTER TABLE `test` CHANGE COLUMN `idcard` `idcard` VARCHAR(30) COLLATE 'latin1_bin' AFTER `id`;

此外,row_format=fixed也提高了速度。row_format=fixed在使用innodb引擎时不可用,但在myisam中可用。我现在得到的结果表如下所示。使用select语句比使用初始表快5倍(时间减少80%)。
注意,我还将'name'和'custom\u value'的排序规则更改为latin1\u bin。这在我的测试设置中确实对速度有很大的影响,我还在想原因。

CREATE TABLE `test` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `idcard` VARCHAR(30) COLLATE 'latin1_bin',
    `name` VARCHAR(30) COLLATE 'latin1_bin',
    `custom_value` VARCHAR(50) COLLATE 'latin1_bin',
    PRIMARY KEY (`id`),
    INDEX `i1` (`idcard`)
)
ENGINE=MyISAM
ROW_FORMAT=FIXED ;

相关问题