Wil*_*zer 5 mysql sql database
我正在寻找有关我目前针对我的服务器运行的一些令人反感的mysql查询的帮助.我的目标是显示最便宜的ebay项目,结束时间不到一个月.
我正在使用MySQL 5.1.
我的查询如下('ebay_items'有~35万行):
explain SELECT `ebay_items`.* FROM `ebay_items`
WHERE (endtime > NOW()-INTERVAL 1 MONTH) ORDER BY price desc\G;
Run Code Online (Sandbox Code Playgroud)
收益率:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: ebay_items
type: range
possible_keys: endtime
key: endtime
key_len: 9
ref: NULL
rows: 71760
Extra: Using where; Using filesort
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
此查询导致使用71760行的昂贵"文件排序".
show indexes on ebay_items;
Run Code Online (Sandbox Code Playgroud)
收益率(我只包括有问题的指数,'endtime'):
*************************** 7. row ***************************
Table: ebay_items
Non_unique: 1
Key_name: endtime
Seq_in_index: 1
Column_name: endtime
Collation: A
Cardinality: 230697
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
*************************** 8. row ***************************
Table: ebay_items
Non_unique: 1
Key_name: endtime
Seq_in_index: 2
Column_name: price
Collation: A
Cardinality: 230697
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Run Code Online (Sandbox Code Playgroud)
仅使用复合结束时间索引(结束时间,价格)的"endtime"键.据我所知,在处理范围查询和"order by"子句时,MySQL不会有效地使用复合索引.
有没有人找到这个问题的良好锻炼?我主要想在数据库级别解决它(通过更智能地使用索引或模式更改),但我愿意接受建议.
我可以避免范围查询的一种方法是让后台任务循环每X小时,并将ebay_items上的枚举类型字段标记为"<1天大","<1周龄","<1个月大",我希望以更清洁的方式解决问题.
有没有办法用order by子句执行MySQL范围查询,以有效的方式查询?
非常感谢您的帮助!
编辑:KohányiRóbert提出了一个很好的观点,我应该澄清我对查询的确切问题.查询导致磁盘I/O被挂起持续时间.如果其中几个查询同时运行,则会备份进程并锁定计算机.我的假设是filesort正在吃掉I/O.
我还应该提到该表正在使用MyISAM引擎.使用InnoDB引擎会提高性能,减少I/O密集吗?再次感谢.
我喜欢你的问题,所以我玩了一些MySQL,并试图找到问题的根源.为此,我创建了一些测试.
我使用一个名为随机数据生成器的工具生成了100.000行样本数据(我认为文档有点过时,但它有效).我传递给的配置文件gendata.pl如下.
$tables = {
rows => [100000],
names => ['ebay_items'],
engines => ['MyISAM'],
pk => ['int auto_increment']
};
$fields = {
types => ['datetime', 'int'],
indexes => [undef]
};
$data = {
numbers => [
'tinyint unsigned',
'smallint unsigned',
'smallint unsigned',
'mediumint unsigned'
],
temporals => ['datetime']
};
Run Code Online (Sandbox Code Playgroud)
我已经运行了两个单独的测试批次:一个使用MyISAM表,另一个使用InnoDB.(所以基本上你在上面的片段中用InnoDB替换了MyISAM.)
该工具创建一个表,其中列被调用pk,col_datetime和col_int.我已将它们重命名为与您的表格列匹配.结果表就在下面.
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| endtime | datetime | YES | MUL | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| price | int(11) | YES | MUL | NULL | |
+---------+----------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)
该工具不创建索引,因为我喜欢它手工创建它们.
CREATE INDEX `endtime` ON `ebay_items` (endtime, price);
CREATE INDEX `price` ON `ebay_items` (price, endtime);
CREATE INDEX `endtime_only` ON `ebay_items` (endtime);
CREATE INDEX `price_only` ON `ebay_items` (price);
Run Code Online (Sandbox Code Playgroud)
我用过的查询.
SELECT `ebay_items`.*
FROM `ebay_items`
FORCE INDEX (`endtime|price|endtime_only|price_only`)
WHERE (`endtime` > '2009-01-01' - INTERVAL 1 MONTH)
ORDER BY `price` DESC
Run Code Online (Sandbox Code Playgroud)
(使用其中一个索引的四种不同查询.我使用的是2009-01-01代替,NOW()因为该工具似乎在2009年左右生成日期.)
以下是EXPLAINMyISAM(顶部)和InnoDB(底部)表中每个索引的上述查询的输出.
id: 1
select_type: SIMPLE
table: ebay_items
type: range
possible_keys: endtime
key: endtime
key_len: 9
ref: NULL
rows: 25261
Extra: Using where; Using filesort
id: 1
select_type: SIMPLE
table: ebay_items
type: range
possible_keys: endtime
key: endtime
key_len: 9
ref: NULL
rows: 21026
Extra: Using where; Using index; Using filesort
Run Code Online (Sandbox Code Playgroud)
id: 1
select_type: SIMPLE
table: ebay_items
type: index
possible_keys: NULL
key: price
key_len: 14
ref: NULL
rows: 100000
Extra: Using where
id: 1
select_type: SIMPLE
table: ebay_items
type: index
possible_keys: NULL
key: price
key_len: 14
ref: NULL
rows: 100226
Extra: Using where; Using index
Run Code Online (Sandbox Code Playgroud)
id: 1
select_type: SIMPLE
table: ebay_items
type: range
possible_keys: endtime_only
key: endtime_only
key_len: 9
ref: NULL
rows: 11666
Extra: Using where; Using filesort
id: 1
select_type: SIMPLE
table: ebay_items
type: range
possible_keys: endtime_only
key: endtime_only
key_len: 9
ref: NULL
rows: 21270
Extra: Using where; Using filesort
Run Code Online (Sandbox Code Playgroud)
id: 1
select_type: SIMPLE
table: ebay_items
type: index
possible_keys: NULL
key: price_only
key_len: 5
ref: NULL
rows: 100000
Extra: Using where
id: 1
select_type: SIMPLE
table: ebay_items
type: index
possible_keys: NULL
key: price_only
key_len: 5
ref: NULL
rows: 100226
Extra: Using where
Run Code Online (Sandbox Code Playgroud)
基于这些我决定使用endtime_only索引进行测试,因为我不得不对MyISAM和InnoDB表运行查询.但正如你所看到的那样,最合乎逻辑的endtime指数似乎是最好的.
为了使用MyISAM和InnoDB表测试查询的效率(关于生成的I/O活动),我编写了以下简单的Java程序.
static final String J = "jdbc:mysql://127.0.0.1:3306/test?user=root&password=root";
static final String Q = "SELECT * FROM ebay_items FORCE INDEX (endtime_only) WHERE (endtime > '2009-01-01'-INTERVAL 1 MONTH) ORDER BY price desc;";
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000; i++)
try (Connection c = DriverManager.getConnection(J);
Statement s = c.createStatement()) {
TimeUnit.MILLISECONDS.sleep(10L);
s.execute(Q);
} catch (SQLException ex) {
ex.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
我在Dell Vostro 1015笔记本电脑上运行MySQL 5.5的Windows二进制文件,Intel Core Duo T6670 @ 2.20 GHz,4 GB RAM.Java程序通过TCP/IP与MySQL服务器进程通信.
我mysqld使用MyISAM和InnoDB(使用Process Explorer)在对表运行测试之前和之后捕获了进程的状态.






基本上,两次运行仅在单个I/O读取的数量上有所不同,当表格使用MyISAM引擎时,这非常大.两次测试都进行了50-60秒.在MyISAM引擎的情况下,CPU的最大负载大约为42%,而使用InnoDB时大约为38.
我不太确定大量I/O读取的含义是什么,但在这种情况下,更小的更好(可能).如果你的表中有更多的列(除了你指定的列之外)并且有一些非默认的MySQL配置(关于缓冲区大小等),MySQL可能会使用磁盘资源.
| 归档时间: |
|
| 查看次数: |
3321 次 |
| 最近记录: |