内部查询速度非常慢。这有什么问题?mySQL
我有一个^join,它自己运行得非常好。打开行结果并开始循环后,我将运行第二个查询,从另一个表中执行计数和日期信息:内部查询速度非常慢。这有什么问题?mySQL,mysql,subquery,distinct,Mysql,Subquery,Distinct,我有一个^join,它自己运行得非常好。打开行结果并开始循环后,我将运行第二个查询,从另一个表中执行计数和日期信息: SELECT * FROM grants INNER JOIN people on grants.volID=people.vol_id INNER JOIN org on grants.orgID=org.orgid order by yearStart DESC 我需要第一次拉取的数据来获得ORID,这就是为什么我要一次一个地检查它们 SELECT
SELECT *
FROM grants
INNER JOIN people on grants.volID=people.vol_id
INNER JOIN org on grants.orgID=org.orgid
order by yearStart DESC
我需要第一次拉取的数据来获得ORID,这就是为什么我要一次一个地检查它们
SELECT COUNT(Distinct Event_ID) as ME, MAX(Sample_Date) as MaxD
FROM results where orgid=%d
如果没有将二次查询推送到组织中,它将以非常快的速度遍历大约230条记录。它减慢到接近20秒!我没有正确地建立计数吗?结果表大约有100000条记录,但我用其他查询处理了这个问题,结果并不是这样的!如果有帮助的话,我如何子查询这个
谢谢你的洞察力 假设results.orgid被索引以排除该问题 如果您使用连接以便MySQL能够进行优化,事情通常会好得多。子查询的性能可能很差 如果我正确理解您的关系,请尝试以下方法:
so it runs like this
Query 1
while($row = mysql_fetch_assoc($result)){
Query 2
while($row1 = mysql_fetch_assoc($result1)){
get some data from 2
} //close 2
get some data from 1 and merge with 2
} //close 1
不要忘记将grants.grantid替换为实际的grants PK列。要找出查询中的性能瓶颈,首先应该使用数据库的解释功能,这样它就可以告诉您它在做什么 听起来您可能没有正确设置某些索引,导致每次循环第一次连接查询的结果时都会扫描不必要的行。检查方法如下例所示: 首先我有一个测试表
SELECT grants.*, org.*, COUNT(Distinct Event_ID) as ME, MAX(Sample_Date) as MaxD
FROM grants
INNER JOIN people on grants.volID=people.vol_id
INNER JOIN org on grants.orgID=org.orgid
LEFT JOIN results ON results.orgid=org.orgid
GROUP BY grants.grantid #whatever your grants PK is
ORDER BY yearStart DESC
接下来我添加几行
mysql> desc test_table;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(64) | YES | | NULL | |
| description | text | YES | | NULL | |
| published | datetime | YES | | NULL | |
| updated | datetime | YES | | NULL | |
| status | tinyint(1) | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
6 rows in set (0.02 sec)
mysql> show indexes from test_table;
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_table | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.01 sec)
mysql> select count(1) from test_table;
+----------+
| count(1) |
+----------+
| 0 |
+----------+
1 row in set (0.02 sec)
接下来,我使用数据库中的EXPLAIN功能来分析我的查询
mysql> INSERT INTO test_table (name, description, published, status) VALUES ('name1','description 1 goes here',now(),1),('name2','description 2 goes here',now(),1),('name3', 'description 3 goes here', now(),1);
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select name, description from test_table where status = 1;
+-------+-------------------------+
| name | description |
+-------+-------------------------+
| name1 | description 1 goes here |
| name2 | description 2 goes here |
| name3 | description 3 goes here |
+-------+-------------------------+
3 rows in set (0.01 sec)
您可以看到它正在扫描3行以查找记录。我怀疑您的数据库正在扫描第二个查询的所有10万行,即您迭代的每一行。这意味着,如果在第一次查询中有100个结果,则有1000万行扫描(100*100K)。您希望rows列尽可能接近1,这意味着它将使用索引查找更快的行
现在,我创建了一个索引,并在WHERE子句中包含了我希望包含的列(我将按顺序添加它们,注意每次都不需要全部使用)
接下来,我再次尝试解释,看看数据库是如何使用索引的,只扫描了一行。您应该优化索引以获得类似的结果
mysql> CREATE INDEX idx_so_example ON test_table (name, description (255), status);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
对于您的数据库,我将在第二个查询中的这3列上添加一个复合索引,假设“results”是基于您的问题的实际表名
mysql> EXPLAIN SELECT name, description, status FROM test_table WHERE name = 'name1' AND status = 1;
+----+-------------+------------+------+----------------+----------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+----------------+----------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | test_table | ref | idx_so_example | idx_so_example | 195 | const | 1 | Using index condition |
+----+-------------+------------+------+----------------+----------------+---------+-------+------+-----------------------+
1 row in set (0.01 sec)
还有一个建议:您的命名约定应该与字段一致,否则您的数据库将成为记忆和编码的噩梦。选择一个标准并坚持使用它,这样如果使用EventId、SampleDate、OrgId great或event_id、sample_date、org_id,但要标准化所有列名和约定,以便在以后尝试查询数据时代码中的语法错误更少。该循环发生在哪种编程语言中?当然,230很快。每个都有400多个。您是否有一个
show create table xxx
或两个要共享的表?是否可以打开声纳进行索引策略ID是否已索引?如果orgid没有在子查询上建立索引,那么它必须读取每一行。否则,它可能只是子查询。MySQL没有很好地优化子查询…如果可能的话,最好是根据结果表进行连接,然后根据您的授权行ID进行分组,以防止重复。orgid在子查询中没有索引。好的,那么添加一个索引,如果仍然很慢,试着使用我在回答中提到的连接——假设我正确理解了这些关系。迈克,谢谢你的深入回复。我正努力坚持下去。所以我想我需要结合您的概念,为这些结果列编制索引,然后重写我的查询以运行连接,就像Kevin在下面提到的那样。他在开场白中写道,他只会在假设我的结果是索引的情况下工作。通过在mySQL中运行上面的代码行。。。“idx_某些_名称”。我需要在下面的查询中引用它吗?或者我可以只调用列名吗?为结果表中的三列编制索引确实大大提高了速度!伟大的威尔想出了答案……很高兴能帮上忙。我正在扩展的一个应用程序最初是在MySQL 3.23上构建的,在添加了慢速查询日志后,我了解到,如果稍后当它变得庞大(数亿行)时尝试索引,索引可能需要数小时甚至数天。今天,我们不那么担心了,但拯救我们的是使用Percona版本的MySQL和异步索引,这样您就可以解释和索引(尝试/错误),而无需等待数小时到数天来解决瓶颈问题。我认为MySQL的更新版本现在提供了类似的但是要考虑的东西。祝你好运这是向我展示一个使用左连接的更好查询的要点。答案是索引。谢谢你们两个!
mysql> EXPLAIN SELECT name, description, status FROM test_table WHERE name = 'name1' AND status = 1;
+----+-------------+------------+------+----------------+----------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+----------------+----------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | test_table | ref | idx_so_example | idx_so_example | 195 | const | 1 | Using index condition |
+----+-------------+------------+------+----------------+----------------+---------+-------+------+-----------------------+
1 row in set (0.01 sec)
CREATE INDEX idx_some_name ON results (Event_ID, Sample_Date, orgid);