約300万件のレコードを含むかなり大きなテーブルがあります。非常に単純なクエリを実行し、このテーブルを他のいくつか(すべてインデックスや主キーを使用)で結合すると、クエリが完了するまでに約25秒かかります。「Handler_read_next」の値は約700万です!
キー順で次の行を読み取る要求の数。範囲制約のあるインデックス列をクエリしている場合、またはインデックススキャンを実行している場合は増分されます。
この問題は、このテーブルが大きくなり始めてから始まったばかりです。
このテーブルで「テーブルの最適化」を実行すると、クエリは約0.02秒で実行され、「Handler_read_next」の値は約1500になります。
どうしてこの違いが極端になるのでしょうか。また、スケジュールされたクエリを設定して、このテーブルを1週間に1回程度最適化する必要があるのでしょうか。それでも、この背後にある意味と、mysqlがこのように動作する理由を知りたいと思います。確かに、このテーブルの行はほとんど削除および更新されていますが、クエリが0.02秒から25秒になるように、わずか1週間で非常にひどく断片化される必要がありますか?
編集:リクエストの後、ここに問題のクエリがあります:
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秒かかるクエリの説明です。