3

我有一个相当大的表,其中包含大约 300 万条记录。当运行一个非常简单的查询时,将这个表连接到其他几个表(都带有索引和/或主键),查询大约需要 25 秒才能完成!“Handler_read_next”的价值约为700万!

按键顺序读取下一行的请求数,如果您正在查询具有范围约束的索引列或正在执行索引扫描,则会增加。

自从这张桌子开始变大以来,这个问题才开始出现。

现在,如果我对该表执行“优化表”,查询将在大约 0.02 秒内运行,“Handler_read_next”的值约为 1500。

差异怎么会如此极端,我真的需要设置一个预定的查询,每周优化一次这个表吗?尽管如此,我还是想知道这背后的含义以及mysql为什么会这样。当然,这个表中的行被删除和更新了很多,但是它是否应该在一周内变得如此严重,以至于查询从 0.02 秒变为 25 秒?

编辑:请求后,这里出现了有问题的查询:

SELECT *
FROM budget_expenses 
  JOIN budget_categories 
    ON  budget_categories.BudgetAreaId = budget_expenses.BudgetAreaId 
    AND budget_categories.BudgetCategoryId = budget_expenses.BudgetCategoryId
  LEFT JOIN budget_types 
    ON  budget_types.BudgetAreaId = budget_expenses.BudgetAreaId 
    AND budget_types.BudgetCategoryId = budget_expenses.BudgetCategoryId 
    AND budget_types.BudgetTypeId = budget_expenses.BudgetTypeId
WHERE budget_expenses.BudgetId = 1 
  AND budget_expenses.ExpenseDate >= '2012-11-25' 
  AND budget_expenses.ExpenseDate <= '2012-12-24' 
  AND budget_expenses.BudgetAreaId = 2 
ORDER BY budget_expenses.ExpenseDate DESC, 
         budget_expenses.ExpenseTime IS NULL ASC, 
         budget_expenses.ExpenseTime DESC

(BudgetAreaId, BudgetCategoryId)是中的主键,budget_categories(BudgetAreaId, BudgetCategoryId, BudgetTypeId)中的主键budget_types。在budget_expenses这 3 个键中是索引,也ExpenseDate有一个索引。此查询返回大约 20 行。

显示创建表:

CREATE TABLE `budget_areas` (
  `BudgetAreaId` int(11) NOT NULL,
  `Name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`BudgetAreaId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE `budget_categories` (
  `BudgetAreaId` int(11) NOT NULL,
  `BudgetCategoryId` int(11) NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) DEFAULT NULL,
  `SortOrder` int(11) DEFAULT NULL,
  PRIMARY KEY (`BudgetAreaId`,`BudgetCategoryId`),
  KEY `BudgetAreaId` (`BudgetAreaId`,`BudgetCategoryId`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1


CREATE TABLE `budget_types` (
  `BudgetAreaId` int(11) NOT NULL,
  `BudgetCategoryId` int(11) NOT NULL,
  `BudgetTypeId` int(11) NOT NULL,
  `Name` varchar(255) DEFAULT NULL,
  `SortId` int(11) DEFAULT NULL,
  PRIMARY KEY (`BudgetAreaId`,`BudgetCategoryId`,`BudgetTypeId`),
  KEY `BudgetAreaId` (`BudgetAreaId`,`BudgetCategoryId`,`BudgetTypeId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

 CREATE TABLE `budget_expenses` (
  `ExpenseId` int(11) NOT NULL AUTO_INCREMENT,
  `BudgetId` int(11) NOT NULL,
  `TempId` int(11) DEFAULT NULL,
  `BudgetAreaId` int(11) DEFAULT NULL,
  `BudgetCategoryId` int(11) DEFAULT NULL,
  `BudgetTypeId` int(11) DEFAULT NULL,
  `Company` varchar(255) DEFAULT NULL,
  `ImportCompany` varchar(255) DEFAULT NULL,
  `Sum` double(50,2) DEFAULT NULL,
  `ExpenseDate` date DEFAULT NULL,
  `ExpenseTime` time DEFAULT NULL,
  `Inserted` datetime DEFAULT NULL,
  `Changed` datetime DEFAULT NULL,
  `InsertType` int(1) DEFAULT NULL,
  `AccountId` int(11) DEFAULT NULL,
  `BankCardId` int(11) DEFAULT NULL,
  PRIMARY KEY (`ExpenseId`),
  KEY `BudgetId` (`BudgetId`),
  KEY `AccountId` (`AccountId`),
  KEY `Company` (`Company`) USING BTREE,
  KEY `ExpenseDate` (`ExpenseDate`),
  KEY `BudgetAreaId` (`BudgetAreaId`),
  KEY `BudgetCategoryId` (`BudgetCategoryId`),
  KEY `BudgetTypeId` (`BudgetTypeId`),
  CONSTRAINT `budget_expenses_ibfk_1` FOREIGN KEY (`BudgetId`) REFERENCES `budgets`    (`BudgetId`)
) ENGINE=InnoDB AUTO_INCREMENT=3604462 DEFAULT CHARSET=latin1

复制粘贴后,我在budget_categories 表上从MyIsam 更改为Innodb。

编辑:从 myisam 到 innodb 的变化没有任何区别。查询现在非常慢,在我优化budget_expenses 表后仅12 小时!

这是查询的解释,现在大约需要 9 秒:

http://jsfiddle.net/dmVPY/1/

4

1 回答 1

1

Ahhh MyISAM....

Try changing the table type (aka 'storage engine') to InnoDB instead.

If you do this, make sure innodb_buffer_pool_size in your my.cnf is a sensible value - the default is too small.

于 2012-12-12T07:58:52.117 回答