简单查询运行缓慢

问题描述 投票:1回答:4

我有以下查询:

SELECT `assignments`.`id`
FROM `assignments` 
WHERE
  `assignments`.`account_id` = 742 
  AND `assignments`.`method` != 'stray' 
  AND (
    `assignments`.`judge_id` = 2349724 
    OR (
      `assignments`.`role_id` IN (234, 8745) 
      AND `assignments`.`judge_id` IS null
    )
  );

此表目前有660万条记录,并且流量很大。我们最慢的查询是上面的查询,即使使用针对account_id,method,法官,id和role_id的索引,它也需要大约0.5 s来运行。

该查询确实使用了提供的索引,但似乎没有太大的帮助。

我在这里可以做些什么来改善查询并将其降低到100ms以下? 660万条记录确实不是那么多= \

我还想补充一点,如果我仅将查询限制在account_id子句(具有自己的索引)中,则速度大致相同。所以我真的很困惑。

以下是仅使用account_id的执行计划:

EXPLAIN select `assignments`.id FROM `assignments`WHERE `assignments`.`account_id` = 374;
+----+-------------+-------------+------------+------+----------------------------------------------------------------------+------------------------------+---------+-------+------+----------+-------------+
| id | select_type | table       | partitions | type | possible_keys                                                        | key                          | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------------+------------+------+----------------------------------------------------------------------+------------------------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | assignments | NULL       | ref  | assignments_account_id_index,assignments_account_id_updated_at_index | assignments_account_id_index | 9       | const |  965 |   100.00 | Using index |
+----+-------------+-------------+------------+------+----------------------------------------------------------------------+------------------------------+---------+-------+------+----------+-------------+

创建表语法:

CREATE TABLE `assignments` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `key` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `batch` int(10) unsigned NOT NULL,
  `account_id` bigint(20) unsigned DEFAULT NULL,
  `season_id` bigint(20) unsigned DEFAULT NULL,
  `judge_id` bigint(20) unsigned DEFAULT NULL,
  `role_id` bigint(20) unsigned DEFAULT NULL,
  `entry_id` bigint(20) unsigned NOT NULL,
  `score_set_id` bigint(20) unsigned NOT NULL,
  `slug` char(8) COLLATE utf8_unicode_ci DEFAULT NULL,
  `method` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `original_method` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `status` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'none',
  `locked` tinyint(1) NOT NULL DEFAULT '0',
  `conflict_of_interest` tinyint(1) NOT NULL DEFAULT '0',
  `raw_score` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `raw_total` double NOT NULL DEFAULT '0',
  `weighted_score` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `weighted_total` double NOT NULL DEFAULT '0',
  `weight_sum` decimal(8,2) NOT NULL DEFAULT '0.00',
  `progress` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `consensus` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `top_pick_preference` tinyint(3) unsigned DEFAULT NULL,
  `top_pick_winner` tinyint(1) NOT NULL DEFAULT '0',
  `top_pick_rank` int(11) DEFAULT NULL,
  `total_votes` bigint(20) unsigned NOT NULL DEFAULT '0',
  `scored_at` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `assignments_key_unique` (`key`),
  KEY `assignments_account_id_index` (`account_id`),
  KEY `assignments_judge_id_index` (`judge_id`),
  KEY `assignments_role_id_index` (`role_id`),
  KEY `assignments_entry_id_index` (`entry_id`),
  KEY `assignments_score_set_id_index` (`score_set_id`),
  KEY `assignments_season_id_index` (`season_id`),
  KEY `assignments_slug_index` (`slug`),
  KEY `assignments_status_index` (`status`),
  KEY `assignments_method_index` (`method`),
  KEY `assignments_original_method_index` (`original_method`),
  KEY `assignments_account_id_updated_at_index` (`account_id`,`updated_at`)
) ENGINE=InnoDB AUTO_INCREMENT=661994447 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
mysql sql indexing query-performance
4个回答
3
投票

由于范围条件会对MySQL利用索引的能力产生负面影响,因此有时可以使用UNION(以查询语法的重复为代价:]

SELECT a.id 
FROM `assignments` AS a
WHERE a.`account_id` = 742 
   AND a.`judge_id` = 2349724 
   AND a.`method` != 'stray' 
UNION ALL
SELECT a.id 
FROM `assignments` AS a
WHERE a.`account_id` = 742 
   AND a.`judge_id` IS NULL AND a.`role_id` IN (234, 8745)
   AND a.`method` != 'stray'
;

account_id, judge_id, method_idaccount_id, judge_id, role_id上的复合索引将大大有利于上述查询的性能。 ...如果我没记错的话,其中的第一个可能会使上半年受益,而其中的第二个可能会使下半年受益(但也存在过度索引的情况)。


2
投票

如果您是我,为了解决问题,我会考虑并做的事情:

检查您将得到的物品数量

SELECT count(*)
FROM `assignments` 
WHERE
  `assignments`.`account_id` = 742 
  AND `assignments`.`method` != 'stray' 
  AND (
    `assignments`.`judge_id` = 2349724 
    OR (
      `assignments`.`role_id` IN (234, 8745) 
      AND `assignments`.`judge_id` IS null
    )
  );

告诉我们您的特定查询应产生多少条记录。

SELECT `assignments`.`id`
FROM `assignments` 
WHERE
  `assignments`.`account_id` = 742;

告诉您与给定帐户关联的分配数量。如果计数比实际选择要快得多,那可能意味着一些。另外,如果有很多记录,则可能需要很长时间才能将其加载到内存中并通过网络发送到另一台计算机。

检查表是否很快?

SELECT `assignments`.`id`
FROM `assignments` limit 0, 100;

如果这很慢,则您的网络可能有问题。

复制数据库

进行转储并重新创建数据库,然后在此新创建的沙箱中运行查询,因此您将看到其他命令是否使您变慢。如果其他查询使您减速,则可能是写入操作导致了减速。如果写锁使您慢下来,那么您可能希望将写操作分组并在特定时间一起执行。

创建适当的索引

由于UUeerdo和GMB已经在其答案中建议了使用where子句中用作过滤器的字段在表上创建多维索引。


1
投票

这可能不是一个完整的答案,但是:您没有正确的索引。复合索引与每列上的individual索引不同。

考虑,改为:

(account_id, judge_id, role_id, method, id)

由于AND /OR/ IN,可能实际上并未使用整个索引,但这至少为查询计划者提供了机会。您可能还想针对Uueerdo的union all查询(已批准)进行尝试。


0
投票

我想到的第一件事是,您不必在查询中的任何地方都具有“赋值”。

select id FROM `assignments`
WHERE `account_id` = 742
AND `method` != 'stray'
AND (`judge_id` = 2349724 
OR (`role_id` IN (234, 8745) 
AND `judge_id` IS null));

应该工作正常。好的,那不会解决您的问题。

也许您可以先查询ID,然后再查询方法,就像这样:

    select id FROM `assignments`
WHERE `account_id` = 742
    AND (`judge_id` = 2349724 
OR (`role_id` IN (234, 8745) 
AND `judge_id` IS null))
AND `method` != 'stray';

只是一个想法。

© www.soinside.com 2019 - 2024. All rights reserved.