間違った実行プランを選択しているため、永久に実行されているwhere条件として従属サブクエリを持つプライマリがあります。
主な質問:
SELECT rtr.id AS id156_,
rtr.procesada AS procesada156_,
rtr.idTransaccion AS idTransa3_156_
FROM
ReservasTiempoReal rtr
INNER JOIN Transacciones t ON t.id=rtr.idTransaccion
INNER JOIN TransaccionLineas tl ON tl.idTransaccion = rtr.idTransaccion
INNER JOIN Productos prod ON prod.id=tl.idProducto
INNER JOIN Proveedores prov ON prov.id=prod.idProveedor
WHERE t.confirmada = 'S'
AND t.codTipoTransaccion = 'RTRCT'
AND t.fechaHora >= '2015-01-20 15:30:59'
AND t.fechaHora <= '2015-01-21 15:30:59'
AND prov.id=77
AND (EXISTS ( SELECT rtr2.id
FROM ReservasTiempoReal rtr2
INNER JOIN Transacciones t2 ON rtr2.idTransaccion = t2.id
WHERE t2.confirmada = 'S'
AND t2.codTipoTransaccion = 'ECTR'
AND t2.idTransaccionOriginal = rtr.idTransaccion));
そしてその実行計画:
赤で表示されているのは、「codTipoTransaccion」列と「confirmada」列を使用した使用済みインデックスです。最初のクエリ(内側のクエリなし)は10行のみを返します。しかし、トランザクションテーブル全体には500万を超えるレコードがあります。そしてそれらのほとんどは属性confirmada = ‘S’を持っています。インデックス「idxConfirmada」(「confirmada」フィールドによるインデックス)を削除すると、クエリの実行には10秒しかかからず、実行プランは次のようになります。
さらに情報を追加するために、プライマリクエリで識別されたレコードのみを使用して依存内部クエリを実行すると、6レコードのみが返されます。使用されたクエリは次のとおりです。
SELECT rtr2.id
FROM ReservasTiempoReal rtr2
INNER JOIN Transacciones t2 ON rtr2.idTransaccion = t2.id
WHERE t2.confirmada = 'S'
AND t2.codTipoTransaccion = 'ECTR'
AND t2.idTransaccionOriginal IN (14748319,
14748519,14750327,14751060,14751126,14751351,14751354,14752902,14754752,
14754785)
「idxConfirmada」インデックスを削除したくないので、正しいプランを選択するためにORMが必要です。また、クエリが休止状態から来ているため、ヒントを使用してインデックスを無視することはできません。
(idxConfirmadaを使用せずに)正しいプランを選択するようにmysqlを作成するにはどうすればよいですか?
私はMYSQL5.1.51を使用しています。
テーブルの詳細を追加
CREATE TABLE `Transacciones` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`fechaHora` datetime NOT NULL ,
`nroTicket` varchar(255) NOT NULL ,
`puntosGenerados` decimal(19,2) DEFAULT NULL,
`creditoPendiente` decimal(19,2) DEFAULT NULL,
`debitoPendiente` decimal(19,2) DEFAULT NULL,
`saldoReal` decimal(19,2) DEFAULT NULL,
`idTransaccionOriginal` bigint(20) DEFAULT NULL,
`codTipoTransaccion` varchar(5) DEFAULT NULL,
`confirmada` varchar(1) NOT NULL,
`nroLote` varchar(5) DEFAULT NULL,
`idMonedaImporteFinal` bigint(20) DEFAULT NULL,
`totalImporteFinal` decimal(19,2) DEFAULT NULL,
`anulada` varchar(1) DEFAULT NULL,
`idLote` bigint(20) DEFAULT NULL,
`online` varchar(1) DEFAULT NULL,
`manualConPIN` varchar(1) DEFAULT NULL,
`manualSinPIN` varchar(1) DEFAULT NULL,
`facturada` varchar(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK2D546D5D771F9D3A` (`idTransaccionOriginal`),
KEY `idxAnulada` (`anulada`),
KEY `idxConfirmada` (`confirmada`),
KEY `idxCodTipoTransaccion` (`codTipoTransaccion`),
KEY `idxFechaHora_CodTipoTransaccion` (`fechaHora`,`codTipoTransaccion`),
KEY `idxNroTicket` (`nroTicket`),
KEY `idxNroLote` (`nroLote`),
KEY `idxFechaHora` (`fechaHora`),
KEY `idxOnline` (`online`),
KEY `idxFacturada` (`facturada`),
CONSTRAINT `FK2D546D5D771F9D3A` FOREIGN KEY (`idTransaccionOriginal`) REFERENCES `Transacciones` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15359563 DEFAULT CHARSET=latin1
CREATE TABLE `ReservasTiempoReal` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`procesada` varchar(1) NOT NULL,
`idTransaccion` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idTransaccion` (`idTransaccion`),
KEY `FK2375B195C078E769` (`idTransaccion`),
KEY `idxProcesada` (`procesada`),
CONSTRAINT `FK2375B195C078E769` FOREIGN KEY (`idTransaccion`) REFERENCES `Transacciones` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=50805 DEFAULT CHARSET=latin1
複合インデックスを使用します。
_INDEX(confirmada, codTipoTransaccion, idTransaccionOriginal, idTransaccion)
_
列は任意の順序にすることができるため、他のニーズを満たすため、および/または_t2
_から他のインデックスを簡単に削除できるように列をシャッフルすることをお勧めします。
これについてさらに議論する必要がある場合は、各テーブルに_SHOW CREATE TABLE
_を指定してください。
編集
For
_JOIN ... ON rtr2.idTransaccion = t2.id
WHERE t2.confirmada = 'S'
AND t2.codTipoTransaccion = 'ECTR'
AND t2.idTransaccionOriginal IN (14748319, 14748519, ...)
_
これを持っている方がおそらく良いでしょう:
_INDEX(codTipoTransaccion, confirmada, idTransaccionOriginal)
_
idTransaccionOriginal
は意図的に最後になります(IN
のため)。
これにより、オプティマイザーは_t2
_で開始するようになります。 idTransaccion
は他のテーブルのインデックスであることがわかります。したがって、JOIN
は効率的であるはずです。 (コールドキャッシュでは、まだ多くのI/Oが存在する可能性があります。)
オプティマイザー(ORMではない)が選択するための_CREATE TABLE
_複数のあまり良くないインデックス。私が提案しているのは、オプティマイザーがすぐに選択できる「より良い」インデックスでなければなりません。オプティマイザーはすべてのインデックスを調べ、(指定されたクエリに対して)明らかに役に立たないインデックスを無視し、統計を調べます。状況によっては(おそらくあなたのものではない)、統計が貧弱で、INDEX
の選択が貧弱になります。 1つのインデックスの「統計」は1つの数値です。バランスの取れた分布を前提としています(_confirmada='S'
_では間違っていると指摘します)。
複合インデックスを使用することは(使用できる場合)、ほとんどの場合、インデックスを短くするよりも優れています。
(無関係)DROP
これらの2番目、冗長として:
_ KEY `idxFechaHora_CodTipoTransaccion` (`fechaHora`,`codTipoTransaccion`),
KEY `idxFechaHora` (`fechaHora`),
_
また、私の提案したインデックスはKEY idxCodTipoTransaccion (codTipoTransaccion)
を不要にします。