我目前正在尝试提高MySQL表的SELECTS速度,并会对如何改进它表示赞赏。
表格中有超过3亿条记录,表格中包含结构标记,日期,值。主键是标签和日期的组合键。该表包含大约600个唯一标记的信息,这些标记最多包含大约400,000行,但行数可以从2000行到超过1,100万行。
针对该表运行的查询是:
SELECT date,
value
FROM table
WHERE tag = "a"
AND date BETWEEN 'x' and 'y'
ORDER BY date
....如果有任何INSERTS,则很少。
我尝试按标记将数据划分为不同数量的分区,但这似乎没有增加速度。
答案 0 :(得分:4)
在这里花点时间阅读我的答案:(与你的答案相似)
5亿行,在0.02秒内扫描1500万行。
MySQL and NoSQL: Help me to choose the right one
然后将表引擎修改为innodb,如下所示:
create table tag_date_value
(
tag_id smallint unsigned not null, -- i prefer ints to chars
tag_date datetime not null, -- can we make this date vs datetime ?
value int unsigned not null default 0, -- or whatever datatype you require
primary key (tag_id, tag_date) -- clustered composite PK
)
engine=innodb;
您可以将以下内容视为主键:
primary key (tag_id, tag_date, value) -- added value save some I/O
但仅当值不是某些LARGE varchar类型时!
像以前一样查询:select
tag_date,
value
from
tag_date_value
where
tag_id = 1 and
tag_date between 'x' and 'y'
order by
tag_date;
希望这有助于:)
修改强>
哦忘了提 - 不要使用alter table将引擎类型从mysiam更改为innodb,而是将数据转储到csv文件中并重新导入到新创建的空innodb表中。
注意我在导出过程中对数据进行排序 - 聚簇索引是KEY!
导出强>
select * into outfile 'tag_dat_value_001.dat'
fields terminated by '|' optionally enclosed by '"'
lines terminated by '\r\n'
from
tag_date_value
where
tag_id between 1 and 50
order by
tag_id, tag_date;
select * into outfile 'tag_dat_value_002.dat'
fields terminated by '|' optionally enclosed by '"'
lines terminated by '\r\n'
from
tag_date_value
where
tag_id between 51 and 100
order by
tag_id, tag_date;
-- etc...
导入强>
以正确的顺序导回到表中!
start transaction;
load data infile 'tag_dat_value_001.dat'
into table tag_date_value
fields terminated by '|' optionally enclosed by '"'
lines terminated by '\r\n'
(
tag_id,
tag_date,
value
);
commit;
-- etc...
答案 1 :(得分:1)
日期字段的基数是什么(即该字段中出现了多少个不同的值)?如果BETWEEN'x'和'y'的日期比WHERE子句的tag ='a'部分更具限制,请尝试使用主键(date,tag)而不是(tag,date),允许使用日期作为索引值。
另外,请注意如何在WHERE子句中指定“x”和“y”。在某些情况下,MySQL会将每个日期字段转换为与您比较的值的非日期隐含类型相匹配。
答案 2 :(得分:1)
我会做两件事 - 首先在标签和日期周围抛出一些索引,如上所示:
alter table table add index (tag, date);
接下来将您的查询分解为主查询和子选择,在您进入主查询时缩小搜索结果:
SELECT date, value
FROM table
WHERE date BETWEEN 'x' and 'y'
AND tag IN ( SELECT tag FROM table WHERE tag = 'a' )
ORDER BY date
答案 3 :(得分:1)
您的查询要求一些东西 - 并且在行数较高的情况下,数据外观可以改变最佳方法。
SELECT date, value
FROM table
WHERE tag = "a"
AND date BETWEEN 'x' and 'y'
ORDER BY date
有些事情可能会减慢此选择查询的速度。
一些建议:
答案 4 :(得分:0)
我认为你进一步改进它的唯一机会是覆盖索引,包含所有三列(标签,数据,值)。这样可以避免表访问。
我不认为分区可以帮助解决这个问题。
答案 5 :(得分:0)
我猜想在(tag, date)
上添加索引会有所帮助:
alter table table add index (tag, date);
请发布有关此查询的解释结果(EXPLAIN SELECT date,value FROM ......)
答案 6 :(得分:0)
我认为value
列是您性能问题的最底层。它不是索引的一部分,因此我们将拥有表访问权限。此外,我认为ORDER BY不太可能严重影响性能,因为它是您索引的一部分,应该订购。
我将通过分区不会真正减少查询的执行时间这一事实来论证我对value
列的怀疑。你可以在没有value
的情况下执行查询,并进一步给出一些结果以及EXPLAIN吗?你真的需要每一行吗?它是什么样的专栏?
干杯!
答案 7 :(得分:0)
尝试将所需日期插入临时表格,然后在临时表格上选择标签并进行排序。
CREATE temporary table foo
SELECT date, value
FROM table
WHERE date BETWEEN 'x' and 'y' ;
ALTER TABLE foo ADD INDEX index( tag );
SELECT date, value
FROM foo
WHERE tag = "a"
ORDER BY date;
如果不起作用,请尝试从标签选择中创建foo。
CREATE temporary table foo
SELECT date, value
FROM table
WHERE tag = "a";
ALTER TABLE foo ADD INDEX index( date );
SELECT date, value
FROM foo
WHERE date BETWEEN 'x' and 'y'
ORDER BY date;