在MySQL中有效查询15,000,000行表

kno*_*orv 26 mysql indexing optimization query-optimization

请考虑以下数据库表:

  • 表"消息"包含13,000,000行(每个消息一行).
  • 表"3,000,000行的用户"(每个用户一行).

以下查询用于获取一堆消息和相应的用户:

SELECT messages.id, messages.message, users.id, users.username
FROM messages
INNER JOIN users ON messages.user_id=users.id 
WHERE messages.id in (?, ?, ?, ? ... a total of 100 "?":s);
Run Code Online (Sandbox Code Playgroud)

在每个查询中提取100条消息.

"messages"的索引是id(主键,BIGINT 不是自动生成的)和user_id.

"users"在id(主键,INT自动生成)上建立索引.

数据库是使用MyISAM的MySQL.

目前查询需要超过3000毫秒才能执行,这使我感到困惑,因为"消息"被索引在"id"上,因此检索正确的行应该非常快.

我的问题是:鉴于描述场景和设置,是一个3000毫秒的查询时间"正常"或我错过了什么?如果需要进一步的详细信息,请告诉我.

更新#1:以下是表定义:

CREATE TABLE messages (
  id bigint(20) NOT NULL DEFAULT '0',
  user_id int(11) NOT NULL DEFAULT '0',
  message varchar(160) NOT NULL DEFAULT '',
  PRIMARY KEY (id),
  KEY user_id (user_id),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE users (
  id int(11) NOT NULL DEFAULT '0',
  username varchar(32) NOT NULL DEFAULT '',
  PRIMARY KEY (id),
  UNIQUE KEY username (username),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

我在定义中观察到的唯一"非标准"事物是"messages.id"是BIGINT而不是INT.这可能是一个暗示吗?

Mik*_*zke 11

我已经在MyISAM表上工作了数十亿行,并且在一些行计数限制之后我发现的一件事是优化器花了太长时间来决定如何处理查询,并错误地执行了一些表扫描.我找不到描述它的确切页面,但我开始在每个查询段上使用FORCE_INDEX,我知道它应该如何请求对象

http://dev.mysql.com/doc/refman/5.1/en/index-hints.html

事实是,如果你使用的是大表,你需要设计每个查询来处理你的索引,所以强制索引没有错.它仍然会扫描表,如果必须,但FORCE_INDEX告诉它不要,除非绝对必须.

另外,如果你的表很大,我认为你的指数也很大.您绝对需要确保您具有正确的配置设置,并且您的key_buffer足够大并且您有足够的i/o.如果你正在运行32位mysql(你不应该这样),那么把你的key_buffer放到1GB(假设你有1GB备用)并用'mysqlreport'检查它的用法

如果您正在运行64位mysql,请选择尽可能大,同时仍然为操作系统留出空间来缓存文件以及您运行的其他任何应用程序,如果可以的话,可能需要几GB.

即使您的查询使用索引,如果索引无法在内存中正确缓冲,您仍然会访问磁盘,并且性能命中与索引大小和磁盘/可用i/o的速度成比例.

就int和big int而言,我见过的唯一明显的性能差异在于对大整数执行计算,例如SUM.大积分上的SUM明显慢于整数,因此我会考虑以不同的大小存储数字,或者如果需要对它们进行频繁计算,则将它们分成两个整数.


Jef*_*and 6

  1. 我们需要解释.
  2. MyISAM提供差的并发性.考虑并发插入可能会让您头疼.有了这么大的数据库,InnoDB可能就是方向.
  3. 如果正在插入和删除消息,如果您的表不是偶尔优化的话,这可能会导致事情发生偏差.此外,MyISAM主键不是群集.再次,有这么大的数据库,InnoDB可能是方向.