你能说出这个查询有什么问题吗?

时间:2010-06-29 07:08:51

标签: mysql

全部

我正在使用单个数据库和大约7个表。确实有数据填充所有表格。 说截止到目前为止大约10k左右。但是会进一步增长,可能会花费数百万,但需要时间。

我的问题是我的查询缓慢获取结果的原因。在非负载条件下查询大约需要10到12秒。我担心如果在负载条件下发生的事情一次会说成千上万的查询?

这是我的示例查询...

$result = $db->sql_query("SELECT * FROM table1,table2,table3,table4,table5 WHERE table1.url = table2.url AND table1.url = table3.url AND table1.url = table4.url AND table1.url = table5.url  AND table1.url='".$uri."'")or die(mysql_error());

$row = $db->sql_fetchrow($result);

$daysA = $row['regtime'];
$days = (strtotime(date("Y-m-d")) - strtotime($row['regtime'])) / (60 * 60 * 24);
if($row > 0 && $days < 2){

$row['data'];
$row['data1'];
//remaining 

}else{ //some code}

5 个答案:

答案 0 :(得分:0)

您的WHERE子句中的某些列可能不是indexed。索引用于快速查找具有特定列值的行。如果没有索引,MySQL必须从第一行开始,然后读取整个表以查找相关行。

您可能会发现EXPLAIN有助于分析您的查询。

答案 1 :(得分:0)

绝对看起来像每个表中url字段的索引是要走的路

答案 2 :(得分:0)

查找JOIN,特别是看看INNER JOINS,LEFT JOINS和OUTER JOINS之间的区别。同时INDEX您要进行查找的所有字段。

答案 3 :(得分:0)

你的索引可能有问题!

在任何情况下,像url这样的长字符串都会导致主键性能下降。在索引中占用了大量空间,因此索引不像它们那样密集,并且每个IO加载的行指针更少。同样使用网址的可能性是99%的字符串以“http://www开头”。所以数据库引擎在决定一行不匹配之前必须比较13个字符。

对此的一个解决方案是使用一些散列函数(如MD5,SHA1甚至CRC32)从字符串中获取原始二进制值,并将此值用作表的主键。 CRC32是一个很好的整数大小的主键,但几乎可以肯定,在某些阶段你会遇到两个散列到相同CRC32值的url,因此你需要存储和比较“url”字符串。其他散列函数返回更长的值(在“原始”模式下分别为16字节和20字节),但碰撞的可能性非常小,以至于不值得烦恼。

答案 4 :(得分:0)

我不确定你是否已经解决了这个问题,但这里是我制作的一些测试数据。有许多因素会影响查询的速度,因此我的简单测试用例可能无法准确反映您的表或数据。但是,它们是一个有用的起点。

首先,创建5个简单的表,每个表具有相同的结构。与表格一样,我在UNIQUE列上使用了url索引:

CREATE TABLE `table1` (
    `id` int(11) NOT NULL auto_increment,
    `url` varchar(255) default NULL,
    PRIMARY KEY  (`id`),
    UNIQUE KEY `url` (`url`)
) ENGINE=InnoDB;

CREATE TABLE table2 LIKE table1;
CREATE TABLE table3 LIKE table1;
CREATE TABLE table4 LIKE table1;
CREATE TABLE table5 LIKE table1;

以下脚本创建一个存储过程,用于向每个表填充10,000行数据:

DELIMITER //
DROP PROCEDURE IF EXISTS test.autofill//
CREATE PROCEDURE test.autofill()
BEGIN
    DECLARE i INT DEFAULT 5;
    WHILE i < 10000 DO
        INSERT INTO table1 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i ));
        INSERT INTO table2 (url) VALUES (CONCAT('wwww.stackoverflow.com/', 10000 - i ));
        INSERT INTO table3 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i + 6000 ));
        INSERT INTO table4 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i + 3000 ));
        INSERT INTO table5 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i + 2000 ));
        SET i = i + 1;
    END WHILE;
END;
//
DELIMITER ;

CALL test.autofill();

现在每个表包含10,000行。您的SELECT语句现在可用于查询数据:

SELECT * 
FROM table1,table2,table3,table4,table5
WHERE table1.url = table2.url
AND table1.url = table3.url
AND table1.url = table4.url
AND table1.url = table5.url
AND table1.url = 'wwww.stackoverflow.com/8000';

这几乎可以立即得到以下结果:

+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+
| id   | url                         | id   | url                         | id   | url                         | id   | url                         | id   | url                         |
+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+
| 7996 | wwww.stackoverflow.com/8000 | 1996 | wwww.stackoverflow.com/8000 | 1996 | wwww.stackoverflow.com/8000 | 4996 | wwww.stackoverflow.com/8000 | 5996 | wwww.stackoverflow.com/8000 |
+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+

EXPLAIN SELECT显示查询速度非常快的原因:

EXPLAIN SELECT * 
FROM table1,table2,table3,table4,table5
WHERE table1.url = table2.url
AND table1.url = table3.url
AND table1.url = table4.url
AND table1.url = table5.url
AND table1.url = 'wwww.stackoverflow.com/8000';

+----+-------------+--------+-------+---------------+------+---------+-------+------+-------------+
| id | select_type | table  | type  | possible_keys | key  | key_len | ref   | rows | Extra       |
+----+-------------+--------+-------+---------------+------+---------+-------+------+-------------+
|  1 | SIMPLE      | table1 | const | url           | url  | 258     | const |    1 | Using index |
|  1 | SIMPLE      | table2 | const | url           | url  | 258     | const |    1 | Using index |
|  1 | SIMPLE      | table3 | const | url           | url  | 258     | const |    1 | Using index |
|  1 | SIMPLE      | table4 | const | url           | url  | 258     | const |    1 | Using index |
|  1 | SIMPLE      | table5 | const | url           | url  | 258     | const |    1 | Using index |
+----+-------------+--------+-------+---------------+------+---------+-------+------+-------------+

select_typeSIMPLE,这意味着没有JOIN语句可以降低速度。

typeconst,这意味着该表最多只能有一个匹配 - 这要归功于UNIQUE索引,它保证两个网址不会相同(参见mysql 5.0 indexes - Unique vs Non Unique有关UNIQUE INDEX)的详细说明。 const列中的type值与您可以获得的值相同。

possible_keyskey使用url密钥。这意味着每个表都使用了正确的索引。

refconst,这意味着MySQL正在将一个常量值(一个不变的值)与索引进行比较。再次,这非常快。

rows等于1. MySQL只需查看每个表中的一行。再一次,这是非常快的。

ExtraUsing index。 MySQL不必对表进行任何额外的非索引搜索。

如果您在每个表的url列上都有索引,那么您的查询应该非常快。