3

約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秒かかるクエリの説明です。

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

4

1 に答える 1

1

ああ、MyISAM...。

代わりに、テーブルタイプ(別名「ストレージエンジン」)をInnoDBに変更してみてください。

これを行う場合は、my.cnfのinnodb_buffer_pool_sizeが適切な値であることを確認してください。デフォルトは小さすぎます。

于 2012-12-12T07:58:52.117 に答える