来自2个表的sql值,包含很多行

时间:2012-10-26 06:09:19

标签: mysql sql

这是我的sql结构:

 `errors_log`
  -> `id`,
  -> `error`,
  -> `create_date`;

 `logs`
  -> `log_id`,
  -> `log_label`,
  -> `log_date`;

首先有超过10万行,第二行有30 000行。 我的问题是如何在一个按日期排序的SQL问题中获取这些值,尽可能最快。我试过了联盟,但是sql需要花费很多时间才最终崩溃。 简而言之,我希望从日期

中获取此表中的数据

2 个答案:

答案 0 :(得分:1)

获取100 000(30 000)条记录的速度相当快(假设您在*_date上有一个索引)。

根据混合表排序数据的速度有多慢(即时分类130 000条记录)。

理想的解决方案可能是将表合并为一个这样的表:

CREATE TYPE logs (
    `id` UNSIGNED INT AUTO_INCREMENT,
    `label` VARCHAR(255),
    `date` DATETIME,
    `type` ENUM('normal', 'error'),
    PRIMARY KEY (`id),
    INDEX (`date`),
    INDEX (`type`, `date`)
)

这样你就可以利用非常迅速的MySQL索引。


另一个解决方案是创建如下所示的关系表:

CREATE TABLE log_dates (
    `id` UNSIGNED INT AUTO_INCREMENT,
    `date` DATETIME,
    `log_id` INT NULL, -- points to logs table (column id)
    `error_id` INT NULL, -- points to errors table
    PRIMARY KEY (`id`),
    INDEX (`date`),
    UNIQUE KEY (`log_id`),
    UNIQUE KEY (`error_id`)
)

记录看起来像:

(NULL, NOW(), $result_from_insert_log, NULL)
(NULL, NOW(), NULL, $result_from_insert_error)

而不是编写病态联接,它会从log_dates中选择所有记录并将它们与错误/日志配对。 但我不会这样做。


您也可以尝试使用VIEWs,但根据some stack answers和几篇博文[1][2],他们不会带来性能提升:

  

在评论中,我喜欢它们方便的SQL封装的视图   通常必须在SQL语句中重复的逻辑   但在整个申请中。有时候方便   虽然成本很高,特别是当TEMPTABLE算法时   使用


我能想到的最后一件事是某种“聚合”表,它会缓存所有日志,会在后台刷新(比如24小时一次,或者在某些事件之后),这很好,当你穿上不需要最新的结果(使用table locking):

CREATE TABLE `logs_aggregate` (
    `id` UNSIGNED INT NOT NULL AUTO_INCREMENT,
    `message` VARCHAR(255),
    `type` ENUM('normal', 'error') DEFAULT 'normal',
    `date` DATETIME,
    PRIMARY KEY (`id`),
    INDEX (`date`)
);

手动表重组:

-- Prevent data change during the progress
LOCK TABLES logs READ,
    errors_log READ,
    logs_aggregate WRITE;

-- Empty aggregated data
TRUNCATE TABLE logs_aggregate;

-- Insert errors
INSERT INTO logs_aggregate (id, message, type, date) VALUES (
    SELECT NULL, error, 'error', create_date
    FROM errors_log
);

-- Insert normal logs
INSERT INTO logs_aggregate (id, message, type, date) VALUES (
    SELECT NULL, log_label, 'normal', log_date
    FROM logs
);

-- Allow writing again
UNLOCK TABLES;

并确保使用将所有记录提取到内存中的模型(例如在php构造ToArray()中),而不是按顺序处理记录。

答案 1 :(得分:0)

所以,SELECT UNION太慢了,你确实希望数据像一样返回一个联合查询,但是你只想进行一次SQL调用?必须妥协这两个要求中的一个。

  1. 进行两次数据库调用。
  2. 两个查询中都有
  3. ORDER BY date
  4. Merge Sort他们。
  5. 由于您的数据已经排序,因此您的合并将在O(n)处运行。