具有 10+ 百万行的 MySQL 表 - 如何使用索引加快搜索速度?

Posted

技术标签:

【中文标题】具有 10+ 百万行的 MySQL 表 - 如何使用索引加快搜索速度?【英文标题】:MySQL table with 10+ million rows - how to speed up searching using indexes? 【发布时间】:2012-05-15 05:05:48 【问题描述】:

我的表结构如下:

如果不存在则创建表 commodity_data (dataid bigint(20) unsigned NOT NULL AUTO_INCREMENT,commodity smallint(6) NOT NULL,market smallint(6)非空,quantity浮点非空,price_min mediumint(9)非空,price_max mediumint(9)非空,price_modal mediumint(9)非NULL,date date NOT NULL,modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 主键 (dataid) ) 引擎=InnoDB 默认字符集=latin1 AUTO_INCREMENT=7059415 ;

我在此表上的 SELECT 将包含 WHERE 子句,其中包含“商品”、“市场”和“日期”中的一个或多个搜索。

我的 ORDER BY 将按 price_min、price_max 或 price_modal 以及大多数其他字段。

该表最终将超过 1000 万行,并将继续以每天大约 5 到 10000 的速度扩展。

我的服务器目前是 VPS 双 2.4Ghz xeon,4GB RAM。

目前唯一的索引在“dataid”字段上。

我已经读到设置索引会有所帮助,我认为这些应该是关于商品、市场和日期的,但我想在继续之前检查这是否正确,除非有更好的方法来做到这一点。表大小将在 600MB 左右,并且还在不断增长。

“commodity”和“market”字段是指其他表中商品和市场的ID。我要么 LEFT JOIN 要么如果它更快,我会将这些表读入 php 中的数组(简单的一级关联数组 id => 名称)。大约有 300 种商品和 2,000 个市场。

目前 SELECT 花费的时间太长,例如带有 WHERE 子句的 COUNT 查询将花费一分钟或更长时间。

【问题讨论】:

【参考方案1】:

如果您在查询文本之前使用EXPLAIN 运行选择查询,mysql 将显示来自优化器的有关查询执行计划的信息,以及可以加快查询速度的建议索引...

【讨论】:

当我运行时: SELECT * FROM 商品数据 WHERE 商品在 (4, 8, 9) AND DATE BETWEEN '2010-01-01' AND '2010-12-31' ORDER BY 商品 ASC , 市场ASC , DATE ASC LIMIT 0 , 30 需要 25 秒。 EXPLAIN 给出以下内容: id:1 select_type:简单表:commodity_data 类型:ALL possible_keys:NULL key:NULL key_len:NULL ref:NULL rows:7119981 Extra:使用where;使用文件排序【参考方案2】:

尝试找出您需要哪些compound 索引:如果您正在搜索commodity AND market AND date,您应该在所有三个索引上都有1(一)个索引。订购很重要,例如,如果您有时不包含market,则订单可能会转到INDEX(commodity,date,market)(最后未使用)。如果 WHERE 变化很大,则案例的多个复合索引可能会有所帮助(例如 INDEX(commodity,date,market)INDEX(market,date,commodity)。请记住,它们在编写/更新时会影响性能。

不过,一分钟还是很长的:确保您的数据库可以通过设置innodb_buffer_pool_sizeas high is it can go 将表加载到内存中。之后,对仍然需要很长时间的查询运行上述 EXPLAINS 并从那里获取。

【讨论】:

我们所说的性能损失有多大?我将在一个块中每天输入 5-10k 行。归根结底,我对 INSERT 花费更长的时间(不会有更新)没有任何问题,只要它们不花费更多倍的时间。 我被告知增加 innodb_buffer_pool_size 可能会在服务器崩溃的情况下导致 InnoDB 损坏,并建议不要增加它。我的服务器上当前设置为 64M。 每天 5-10k 几乎没有,所以你应该没问题。 Innodb_buffer_pool_size 不会导致损坏。为 innodb_flush_log_at_trx_commit 设置不适当的值,然后猛拉服务器的电源可能会导致它。但无论如何,请忽略彼得扎尔采夫在给出的链接中的建议。这不像他知道他的 MySQL 东西或任何东西 [/sarcasm]。 我不能无视任何建议。我的服务器提供商的管理员告诉我,如果突然断电,会有风险(如您所述)。我将考虑创建几个多列索引——这似乎是加快我的 SELECT 速度方面最直接的改变。 这个人是否认为将 innodb_buffer_pool_size 设置得较低会降低风险?只要刷新日志设置仍然存在,它就不会降低风险,您仍然可能会丢失数据。因为这个而减少 innodb_buffer_pool_size 的数量是疯狂的,除非你有一个非常奇怪的情况,即 UPS 能够在电源故障时正确关闭系统但只有不到几秒钟的时间......

以上是关于具有 10+ 百万行的 MySQL 表 - 如何使用索引加快搜索速度?的主要内容,如果未能解决你的问题,请参考以下文章

具有百万行的数据库表

在 Python 中合并具有数百万行的两个表

具有数百万行的 Django 表

mysql中数百万行的基于键的分区

如何在 SQL Server 中更新具有数百万行的大表?

如何使用 pandas 或 python 将具有数百万行的表从 PostgreSQL 复制到 Amazon Redshift