我想加快这段代码。这是需要时间的查询。如果我将从100返回的行数更改为10,则需要几乎相同的时间(约2秒)。 GET基于用户排序/搜索输入。如何提高速度呢?这个项目表有大约2374744行,而bot表大约有20行。
$bot = " && user_items_new.bot_id != '0'";
if ($_GET['bot'] != 0) {
$bot = " && user_items_new.bot_id='".$_GET['bot']."'";
}
$name = '';
if (strlen($_GET['name']) > 0) {
$name = " && user_items_new.name LIKE '%".$_GET['name']."%'";
}
$min = '';
if (strlen($_GET['min']) > 0) {
$min = " && steam_price >= '".$_GET['min']."'";
}
$max = '';
if (strlen($_GET['max']) > 0) {
$max = " && steam_price <= '".$_GET['max']."'";
}
$order = '';
if ($_GET['order'] == 'price_desc') {
$order = "ORDER BY steam_price DESC, user_items_new.name ASC";
} elseif ($_GET['order'] == 'price_asc') {
$order = "ORDER BY steam_price ASC, user_items_new.name ASC";
} elseif ($_GET['order'] == 'name_desc') {
$order = "ORDER BY user_items_new.name DESC";
} else {
$order = "ORDER BY user_items_new.name ASC";
}
$limit = $_GET['start'];
$limit .= ', 100';
$i = 0;
$sql = mysql_query("SELECT user_item_id, user_items_new.bot_id AS item_bot_id, sticker, `key`, `case`, exterior, stattrak, image, user_items_new.name AS item_name, steam_price, color, bots_new.bot_id, bots_new.name AS bot_name, withdraw_enabled FROM user_items_new LEFT JOIN bots_new ON user_items_new.bot_id=bots_new.bot_id WHERE steam_price > '0.1' && deposit_start='0' && deposited='0' && user_id='0' && withdraw_enabled='1' ".$bot." ".$name." ".$min." ".$max." ".$order." LIMIT ".$limit)or die(mysql_error());
while ($item = mysql_fetch_assoc($sql)) {
//...
}
项目表看起来像这样(从phpMyAdmin转储):
CREATE TABLE IF NOT EXISTS `user_items_new` (
`user_item_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`bot_id` int(11) NOT NULL,
`item_original_id` varchar(22) NOT NULL,
`item_real_id` varchar(22) NOT NULL,
`class_id` varchar(22) NOT NULL,
`weapon_id` int(11) NOT NULL,
`name` text NOT NULL,
`image` text NOT NULL,
`case` int(11) NOT NULL,
`key` int(11) NOT NULL,
`sticker` int(11) NOT NULL,
`capsule` int(11) NOT NULL,
`holo` int(11) NOT NULL,
`name_tag` int(11) NOT NULL,
`access_pass` int(11) NOT NULL,
`stattrak` int(11) NOT NULL,
`color` varchar(32) NOT NULL,
`exterior` text NOT NULL,
`steam_price` double NOT NULL,
`deposited` int(11) NOT NULL,
`deposit_start` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=5219079 DEFAULT CHARSET=utf8;
ALTER TABLE `user_items_new`
ADD PRIMARY KEY (`user_item_id`), ADD KEY `user_id` (`user_id`), ADD KEY `bot_id` (`bot_id`);
ALTER TABLE `user_items_new`
MODIFY `user_item_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5219079;
然后是机器人表:
CREATE TABLE IF NOT EXISTS `bots_new` (
`bot_id` int(11) NOT NULL,
`name` varchar(64) NOT NULL,
`username` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`deposit_enabled` int(11) NOT NULL,
`withdraw_enabled` int(11) NOT NULL,
`ident` varchar(32) NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
ALTER TABLE `bots_new`
ADD PRIMARY KEY (`bot_id`);
修改(添加精美印刷的SELECT)
SELECT user_item_id, user_items_new.bot_id AS item_bot_id, sticker,
key, case, exterior, stattrak, image, user_items_new.name AS item_name,
steam_price, color, bots_new.bot_id, bots_new.name AS bot_name,
withdraw_enabled
FROM user_items_new
LEFT JOIN bots_new ON user_items_new.bot_id=bots_new.bot_id
WHERE user_items_new.bot_id != '0' && deposit_start='0' && deposited='0' && user_id='0' && withdraw_enabled='1'
ORDER BY user_items_new.name ASC
LIMIT , 100
答案 0 :(得分:1)
如何加快速度......
首先,在具有相等比较谓词的列上添加复合索引,例如
... ON user_items_new (user_id,deposited,deposit_start)
如果谓词过滤掉大量行,这将是有益的。例如,如果少于10%的行满足条件user_id = 0
。
顺便说一句,谓词withdraw_enabled='1'
将否定&#34;外在性&#34; LEFT JOIN
的。{如果省略关键字LEFT
,则查询的结果将是等效的。
另一个问题是ORDER BY
将导致&#34;使用filesort&#34;对行进行排序的操作。在应用LIMIT
子句之前,需要对整个集进行排序。因此,我们不希望LIMIT 10
比LIMIT 1000
更快,除了客户转移额外990行的额外时间。 (关于整个集合的排序并不完全正确;在某些情况下,MySQL可以在识别出第一个&#34;限制行数后中止排序操作。但是MySQL仍然需要通过整套以获得第一行。)
将ORDER BY
子句中的列添加到索引后,可能会在具有等式谓词的列之后添加。这些需要紧跟在等式谓词中引用的列之后出现。可能还需要在ORDER BY
子句中指定相同的列。
假设当前查询包括:
...
WHERE ...
&& deposit_start='0' && u.deposited='0' && u.user_id='0' ...
...
ORDER BY steam_price ASC, user_items_new.name ASC
该指数可能合适:
... ON user_items_new (user_id,deposited,deposit_start,steam_price,name)
EXPLAIN
的输出将显示该索引是否用于查询。除了前三列的相等比较之外,MySQL可以对索引使用范围扫描操作来满足steam_price >
谓词。
还有InnoDB缓冲池的问题;分配多少内存来保存内存中的索引和数据页,以避免存储i / o。
要避免查找基础表中的数据页,可以考虑为查询创建覆盖索引。覆盖索引包括从表引用的列的所有,因此可以从索引完全满足查询。 EXPLAIN输出将显示&#34;使用索引&#34;如果查询使用覆盖索引,则在Extra列中。 (但是索引中的列数和总行大小是有限制的。当表行很大时,这将最有利于查询的性能,并且索引中列的大小是该列的一小部分。总表格行。
答案 1 :(得分:0)
使用该大小的表,可以用来优化查询的最简单的技巧之一是在where子句中使用的字段上添加索引。这允许解析器为您最常使用的查询预分类。
例如,你应该看到显着的收益:
ALTER TABLE user_items_new ADD INDEX (steam_price);
数据和数据类型在确定实际收益方面有很长的路要走。在所有字段上添加索引将导致查询效率倒退。所以更多不一定更好。
答案 2 :(得分:0)
您的查询速度很慢,因为您对user_items_new
表的查询需要检查120万行。虽然您有user_item_id
,user_id
和bot_id
的索引,但这些索引到目前为止只能过滤您的搜索结果。
您需要在某些数据列上添加索引。您想要添加哪些索引(以及它们中的任何一个是否是复合索引)将取决于表的实际内容,并且在没有更多信息的情况下很难推荐。
您需要根据哪些列添加索引,其中不同的值会减少必须显着查看的数据;例如,withdraw_enabled
上的索引不太可能获得太多,除非很少行具有withdraw_enabled == 1.如果您的行中只有很少的行具有steam_price&gt; = 0.1,则steam_price的索引将是有益的。 / p>