使用主键进行排序时进行文件排序

use*_*477 5 mysql optimization order-by

过去两天我一直为此而头疼。

CREATE TABLE `clients` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `guarantor_name` varchar(50) NOT NULL,
    `guarantor_dob` date DEFAULT NULL,
    `guarantor_relationship` int(11) DEFAULT '14',
    `telephone_number` varchar(50) DEFAULT NULL,
    `telephone_type` int(11) DEFAULT '7',
    `state` varchar(50) DEFAULT '',
    `pincode` mediumint(6) unsigned NOT NULL,
    `income` int(11) DEFAULT NULL,
    `family_income` int(11) DEFAULT NULL,
    `name` varchar(100) NOT NULL,
    `gender` int(11) DEFAULT '2',
    `marital_status` int(11) DEFAULT '1',
    `reference` varchar(100) DEFAULT NULL,
    `reference_type` int(11) DEFAULT '4',
    `reference2` varchar(50) DEFAULT NULL,
    `reference2_type` int(11) DEFAULT '2',
    `spouse_name` varchar(100) DEFAULT NULL,
    `date_of_birth` date DEFAULT NULL,
    `spouse_date_of_birth` date DEFAULT NULL,
    `address` text NOT NULL,
    `active` tinyint(1) NOT NULL DEFAULT '1',
    `inactive_reason` int(11) DEFAULT '1',
    `date_joined` date DEFAULT NULL,
    `grt_pass_date` date DEFAULT NULL,
    `center_id` int(11) DEFAULT NULL,
    `created_at` datetime DEFAULT '2013-01-06 14:29:16',
    `deleted_at` datetime DEFAULT NULL,
    `updated_at` datetime DEFAULT NULL,
    `deceased_on` date DEFAULT NULL,
    `created_by_user_id` int(11) NOT NULL,
    `other_income` int(11) DEFAULT NULL,
    `total_income` int(11) DEFAULT NULL,
    `poverty_status` varchar(10) DEFAULT NULL,
    `caste` int(11) DEFAULT '1',
    `religion` int(11) DEFAULT '1',
    `created_by_staff_member_id` int(11) NOT NULL,
    `claim_document_status` int(11) DEFAULT '1',
    `claim_document_recieved_by` int(11) DEFAULT NULL,
    `cliam_document_recieved_on` date DEFAULT NULL,
    `town_classification` int(11) DEFAULT '1',
    `upload_reference` int(11) DEFAULT NULL,
    `picture_file_name` varchar(50) DEFAULT NULL,
    `picture_content_type` varchar(50) DEFAULT NULL,
    `picture_file_size` int(11) DEFAULT NULL,
    `picture_updated_at` datetime DEFAULT NULL,
    `application_form_file_name` varchar(50) DEFAULT NULL,
    `application_form_content_type` varchar(50) DEFAULT NULL,
    `application_form_file_size` int(11) DEFAULT NULL,
    `application_form_updated_at` datetime DEFAULT NULL,
    `fingerprint_file_name` varchar(50) DEFAULT NULL,
    `fingerprint_content_type` varchar(50) DEFAULT NULL,
    `fingerprint_file_size` int(11) DEFAULT NULL,
    `fingerprint_updated_at` datetime DEFAULT NULL,
    `client_group_id` int(10) unsigned DEFAULT NULL,
    `priority_sector_list_id` int(10) unsigned DEFAULT NULL,
    `upload_id` int(10) unsigned DEFAULT NULL,
    `psl_sub_category_id` int(10) unsigned DEFAULT NULL,
    `occupation_id` int(10) unsigned DEFAULT NULL,
    `client_identifier` varchar(50) NOT NULL,
    `age` int(11) DEFAULT NULL,
    `age_as_on_date` date DEFAULT NULL,
    `is_loan_applicant` tinyint(1) DEFAULT '0',
    `occupation_field` varchar(50) DEFAULT NULL,
    `father_name` varchar(100) DEFAULT NULL,
    `father_dob` date DEFAULT NULL,
    `ews` int(11) DEFAULT '1',
    `residence_stability` int(11) DEFAULT '1',
    `owner_status` int(11) DEFAULT '1',
    `no_of_children` varchar(50) DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `index_clients_client_group` (`client_group_id`),
    KEY `index_clients_psl_sub_category` (`psl_sub_category_id`),
    KEY `index_dedupe_variables`
    (`deleted_at`,`state`,`reference_type`,`reference`,`id`,`client_identifier`)
) ENGINE=InnoDB AUTO_INCREMENT=234631 DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

这是桌子。嗯,这是一张很长的桌子。现在我有查询

SELECT SQL_NO_CACHE `id`, `client_identifier`, `guarantor_name`, `guarantor_dob`,
`guarantor_relationship`, `telephone_number`, `telephone_type`, `state`, `pincode`,
`income`, `family_income`, `name`, `gender`, `marital_status`, `reference`,
`reference_type`, `reference2`, `reference2_type`, `father_name`, `father_dob`,
`ews`, `residence_stability`, `owner_status`, `no_of_children`, `spouse_name`, `age`,
`age_as_on_date`, `date_of_birth`, `spouse_date_of_birth`, `active`, `inactive_reason`,
`date_joined`, `grt_pass_date`, `center_id`, `created_at`, `updated_at`, `deceased_on`,
`created_by_user_id`, `other_income`, `total_income`, `poverty_status`, `caste`,
`religion`, `created_by_staff_member_id`, `claim_document_status`,
`claim_document_recieved_by`, `cliam_document_recieved_on`, `town_classification`,
`is_loan_applicant`, `occupation_field`, `upload_reference`, `picture_file_name`,
`picture_content_type`, `picture_file_size`, `picture_updated_at`,
`application_form_file_name`, `application_form_content_type`,
`application_form_file_size`, `application_form_updated_at`,
`fingerprint_file_name`, `fingerprint_content_type`, `fingerprint_file_size`,
`fingerprint_updated_at`, `priority_sector_list_id`, `occupation_id`,
`client_group_id`, `upload_id`, `psl_sub_category_id`
FROM `clients` use index(primary,index_dedupe_variables)
WHERE `deleted_at` IS NULL AND state = 'Maharashtra'
and reference_type = 4 and reference LIKE '%8858' ORDER BY id;
Run Code Online (Sandbox Code Playgroud)

我已经创建了索引

(deleted_at,state,reference_type,reference,id) 
Run Code Online (Sandbox Code Playgroud)

当我解释这个查询时,我得到

** * ** * ** * ** * * 1. 行* ** * ** * ** * ** *
d id: 1
select_type: SIMPLE
table: clients
type: ref
possible_keys: index_dedupe_variables
key: index_dedupe_variables
key_len: 167
ref:const、const、const
行:119122
额外:使用 where;
在集合中使用文件排序1 行(0.00 秒)

我尝试增加排序缓冲区大小以及 max_heap_table_size 但我无法摆脱 filesort 但没有用。我什至试图强制索引也不起作用。我想使用覆盖索引,但考虑到列数可能听起来很糟糕。我不确定我哪里出错了:(。

Mic*_*bot 4

KEY `index_dedupe_variables`
(`deleted_at`,`state`,`reference_type`,`reference`,`id`,`client_identifier`)
Run Code Online (Sandbox Code Playgroud)

尝试删除该索引并将其替换为以下索引:

KEY `new_index`
(`deleted_at`,`state`,`reference_type`,`id`)
Run Code Online (Sandbox Code Playgroud)

即使在使用索引时,也仅使用索引的有用部分;该索引不考虑无法使用索引的第一个实例右侧的列。

在查询中, 'reference'在左侧使用通配符,使得索引的该列无用,并消除了索引中“id”的使用。

您的解释计划告诉您正在发生这种情况:

ref: const,const,const
Run Code Online (Sandbox Code Playgroud)

由此,您可以看出查询实际上仅使用索引的前三列。

通过重新定义索引以消除不可用的“引用”列,我们可以使用索引的所有 4 列,并且由于索引已经按照您想要的顺序排序,因此我们可以这样做:

WHERE `deleted_at` IS NULL
  AND state = 'Maharashtra'
  AND reference_type = 4 
  AND reference LIKE '%8858' 
ORDER BY deleted_at, state, reference_type, id
Run Code Online (Sandbox Code Playgroud)

我们并不真的希望它们按前三列排序,但由于它们都是相等比较,因此按它们排序不会改变结果,并且对于优化器来说应该“显而易见”,它可以简单地返回结果索引顺序...不需要文件排序。

EXPLAIN应该更改为“使用位置”,并且可能更改为“使用索引”(因为这可能意味着“使用索引进行查找”,即使它不是覆盖索引。)

即使您只有“id”,优化器也可能会流行并且不使用文件排序,ORDER BY因此您可以在更改索引后尝试两种方式。

另外,从您的查询中删除use index。不应该需要它。