在Mysql 5.6中使用100.000.000行在innodb表中加速查询的最佳方法

时间:2014-04-09 10:37:46

标签: mysql performance select innodb

我有一个包含7000万行的Mysql 5.6表,但它会在几周内增长到1亿多行或更多。

我有一台专用机器,配有500GB磁盘和4GB RAM,innodb_buffer_pool_size设置为2GB。

数据库使用99%来选择,1%用于插入(每月一次)。

最重要的列是descripcion_detallada_producto varchar(300),这是90%的时间内选择的目标。

我的表是:

    CREATE TABLE `t1` (
      `N_orden` bigint(20) NOT NULL DEFAULT '0',
      `Fecha` varchar(15) COLLATE latin1_spanish_ci DEFAULT NULL,
      `Ncm` int(11) NOT NULL,
      `Origen` int(11) NOT NULL,
      `Adquisicion` int(11) NOT NULL,
      `Medida_Estadistica` int(11) NOT NULL,
      `Unidad_Comercializacion` varchar(30) COLLATE latin1_spanish_ci DEFAULT NULL,
      `Descripcion_Detallada_Producto` varchar(300) COLLATE latin1_spanish_ci DEFAULT NULL,
      `Cantidad_Estadistica` double DEFAULT NULL,
      `Peso_Liquido_Kg` double DEFAULT NULL,
      `Valor_Fob` double DEFAULT NULL,
      `Valor_Frete` double DEFAULT NULL,
      `Valor_Seguro` double DEFAULT NULL,
      `Valor_Unidad` double DEFAULT NULL,
      `Cantidad` double DEFAULT NULL,
      `Valor_Total` double DEFAULT NULL,
      PRIMARY KEY (`N_orden`),
      KEY `Ncm` (`Ncm`),
      KEY `Origen` (`Origen`),
      KEY `Adquisicion` (`Adquisicion`),
      KEY `Medida_Estadistica` (`Medida_Estadistica`),
      KEY `Descripcion_Detallada_Producto` (`Descripcion_Detallada_Producto`),
      CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`Ncm`) REFERENCES `ncm` (`Ncm`),
      CONSTRAINT `t1_ibfk_2` FOREIGN KEY (`Origen`) REFERENCES `paises` (`Codigo_Pais`),
      CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`Adquisicion`) REFERENCES `paises` (`Codigo_Pais`),
      CONSTRAINT `t1_ibfk_4` FOREIGN KEY (`Medida_Estadistica`) REFERENCES `medida_estadistica` (`Codigo_Medida_Estadistica`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_spanish_ci;

我的问题:今天SELECT query using LIKE '%whatever%'通常需要5到7分钟,有时甚至更多。从我理解的地方开始,只要使用varchar索引,无论%'使用,但我需要有可能使用左右通配符搜索字符串,而无需每次搜索等待约7分钟。我该怎么办?

2 个答案:

答案 0 :(得分:1)

解决问题的正确方法是查看针对表运行的所有查询及其相对频率。你只给了我们一部分。你甚至没有说出它与哪个领域有关。既然你说"最重要的一列是descripcion_detallada_producto varchar(300),它是90%的时间内选择目标的地方"我假设你只需要优化

WHERE descripcion_detallada_producto LIKE '%wathever%'

正如Vatev已经说过的那样,你可能应该使用全文搜索 - 它与LIKE谓词的语义(和句法上)不同。此外,您应该将descripcion_detallada_producto属性拆分为它自己的关系,以减少从磁盘读取大行到内存中的缓冲区刷新效果。

答案 1 :(得分:0)

如果要搜索可能位于文本列中任何位置的整个单词,则应考虑使用全文索引,这些索引显然与通配符搜索的使用方式不同。如果您不确定如何搜索全文索引,可以随时获得帮助。

执行以下搜索不会使用任何索引。相反,它将扫描表数据的所有行,并且您将受到磁盘读取(以及任何相关的磁盘碎片,这通常不是问题,因为我们通常不扫描表):

SELECT * FROM t1
WHERE Descripcion_Detallada_Producto LIKE `%whatever%'

以下查询只扫描Descripcion_Detallada_Producto上的索引,该索引将充当“覆盖”索引(请注意,select中的列会产生差异):

SELECT N_orden FROM t1
WHERE Descripcion_Detallada_Producto LIKE `%whatever%'

扫描索引而不是实际表数据的优势在于,扫描时读取的数据量最小化,理想情况下使用大innodb_buffer_pool_size,该索引将在内存中,这将是避免磁盘搜索。

获得N_orden值后,您就可以从表格数据中检索单个记录。

其他信息

考虑减小列的大小(bigint为N_orden的unsigned int)并减小Descripcion_Detallada_Producto的大小。即使VARCHAR仅使用表数据中的实际字节(加上长度),每个索引条目实际上使用最大值,因此减少索引中的VARCHAR列大小将提高索引扫描速度。

此外,如果您有类别,请将搜索限制为所选类别,并在类别+说明上创建多列索引。以下内容只需要通过将搜索限制为特定类别来扫描类别和描述的多列索引的一部分:

SELECT N_orden FROM t1
WHERE Category = 1
  AND Descripcion_Detallada_Producto LIKE `%whatever%'

最后,考虑删除通配符前缀。让用户至少键入型号的开头。