查询中的查询速度非常慢。这有什么问题? mySQL

Incredibly slow query inside query. What is wrong with this? mySQL

SELECT * 
FROM grants 
    INNER JOIN people on grants.volID=people.vol_id 
    INNER JOIN org on grants.orgID=org.orgid 
order by yearStart DESC

我有这个 ^ join,它 运行 本身就很棒。打开行结果并开始遍历它后,我 运行 第二个查询从另一个 table:

执行计数和日期信息
SELECT COUNT(Distinct Event_ID) as ME, MAX(Sample_Date) as MaxD 
FROM results where orgid=%d 

我需要第一次拉取的数据来获取 ordID,这就是为什么我一次要检查它们的原因

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

如果不将辅助查询推入其中,它 运行 会非常快速地处理组织中的大约 230 条记录。它减慢了将近 20 秒!我没有正确构建 Count Distinct 吗?结果 table 大约有 100,000 条记录,但我用其他查询浏览了那个东西,它不会像这样陷入困境!如果有帮助,我该如何子查询?

感谢您的任何见解。

假设 results.orgid 已编入索引以排除该问题...

如果使用 JOIN,事情通常会好很多,这样 MySQL 可以优化。子查询的性能可能很差。

如果我正确理解你的关系,试试这个:

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

不要忘记将 grants.grantid 替换为您的实际资助 PK 列。

要找出查询中的性能瓶颈,您应该做的第一件事是使用数据库的 EXPLAIN 功能,以便它可以告诉您它在做什么。 https://dev.mysql.com/doc/refman/5.0/en/explain.html

听起来您可能没有正确设置某些索引,导致每次循环遍历第一个连接查询的结果时都扫描不必要的行。一种检查方法如下例所示:

首先我有一个测试table

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)

接下来我添加几行

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)

接下来我使用数据库中的 EXPLAIN 功能来分析我的查询

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 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

您可以看到它正在扫描3 行 来查找记录。我怀疑您的数据库正在为第二个查询扫描所有 100K 行,遍历每一行。这意味着如果第一个查询中有 100 个结果,则您有 1000 万行扫描 (100 * 100K)。您希望行列尽可能接近 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

接下来我再次尝试 EXPLAIN 并查看数据库如何使用索引并且只扫描了 1 行 。您应该优化您的索引以获得类似的结果。

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)

对于你的数据库,我会在你的第二个查询中的那 3 列上添加一个复合索引,假设 'results' 是一个基于你的问题的实际 table 名称。

CREATE INDEX idx_some_name ON results (Event_ID, Sample_Date, orgid);

还有一个建议:字段的命名约定应该保持一致,否则会使数据库成为记忆和编码的噩梦。选择一个标准并坚持使用它,所以如果使用 EventId、SampleDate、OrgId 很棒或 event_id、sample_date、org_id,但标准化所有列名称和约定,以便以后尝试的代码中的语法错误更少查询数据。