【发布时间】:2020-11-21 22:38:00
【问题描述】:
我有这个简单的查询
SELECT item_code, stock_value, name, warehouse
FROM `tabStock Ledger Entry` sle
WHERE posting_date <= '2020-08-01'
AND warehouse = 'bom'
ORDER BY timestamp(posting_date, posting_time) DESC,
Creation DESC
1000 条记录几乎需要 3 秒。如果没有 Order By 子句,查询整个表只需不到 1 秒。该表本身目前有 1M+ 条记录。
show processlist 总是卡在 State Creating Sort Index 上。
解释查询显示:
+------+-------------+-------+------+------------------------------+-----------+---------+-------+--------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+------------------------------+-----------+---------+-------+--------+----------------------------------------------------+
| 1 | SIMPLE | sle | ref | posting_sort_index,warehouse | warehouse | 563 | const | 127740 | Using index condition; Using where; Using filesort |
+------+-------------+-------+------+------------------------------+-----------+---------+-------+--------+----------------------------------------------------+
表索引如下:
+-----------------------+------------+-------------------------------+--------------+--------------+--
| Table | Non_unique | Key_name | Seq_in_index | Column_name | C
+-----------------------+------------+-------------------------------+--------------+--------------+--
| tabStock Ledger Entry | 0 | PRIMARY | 1 | name | A
| tabStock Ledger Entry | 1 | item_code | 1 | item_code | A
| tabStock Ledger Entry | 1 | parent | 1 | parent | A
| tabStock Ledger Entry | 1 | posting_sort_index | 1 | posting_date | A
| tabStock Ledger Entry | 1 | posting_sort_index | 2 | posting_time | A
| tabStock Ledger Entry | 1 | posting_sort_index | 3 | name | A
| tabStock Ledger Entry | 1 | voucher_no_voucher_type_index | 1 | voucher_no | A
| tabStock Ledger Entry | 1 | voucher_no_voucher_type_index | 2 | voucher_type | A
| tabStock Ledger Entry | 1 | warehouse | 1 | warehouse | A
| tabStock Ledger Entry | 1 | warehouse | 2 | posting_date | A
+-----------------------+------------+-------------------------------+--------------+--------------+--
为(posting_date,warehouse)或(warehouse,posting_date)添加了索引,但它没有帮助..查询似乎总是使用文件排序
innodb_buffer_pool_size 是 2G..out of 4G RAM。我认为它足够了..它不是一个巨型数据库
SHow Create table如下:
+-----------------------+---------------------------------------------------------------
| Table | Create Table
+-----------------------+---------------------------------------------------------------
| tabStock Ledger Entry | CREATE TABLE `tabStock Ledger Entry` (
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`creation` datetime(6) DEFAULT NULL,
`modified` datetime(6) DEFAULT NULL,
`modified_by` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`owner` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`docstatus` int(1) NOT NULL DEFAULT 0,
`parent` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`parentfield` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`parenttype` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`idx` int(8) DEFAULT NULL,
`actual_qty` decimal(18,6) NOT NULL DEFAULT 0.000000,
`warehouse` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`qty_after_transaction` decimal(18,6) NOT NULL DEFAULT 0.000000,
`fiscal_year` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`company` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`serial_no` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`incoming_rate` decimal(18,6) NOT NULL DEFAULT 0.000000,
`stock_queue` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`item_code` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`voucher_detail_no` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`project` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`stock_value_difference` decimal(18,6) NOT NULL DEFAULT 0.000000,
`stock_uom` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`voucher_type` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`batch_no` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`valuation_rate` decimal(18,6) NOT NULL DEFAULT 0.000000,
`posting_date` date DEFAULT NULL,
`voucher_no` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`stock_value` decimal(18,6) NOT NULL DEFAULT 0.000000,
`is_cancelled` varchar(140) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`posting_time` time(6) DEFAULT NULL,
`outgoing_rate` decimal(18,6) NOT NULL DEFAULT 0.000000,
`_comments` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`_liked_by` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`_assign` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`_user_tags` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`to_rename` int(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`name`),
KEY `item_code` (`item_code`),
KEY `parent` (`parent`),
KEY `posting_sort_index` (`posting_date`,`posting_time`,`name`),
KEY `voucher_no_voucher_type_index` (`voucher_no`,`voucher_type`),
KEY `warehouse` (`warehouse`,`posting_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED
+-----------------------+---------------------------------------------------------------
更多
我删除了时间戳功能和仅通过发布日期排序..从 mariadb 控制台运行查询..最后,加载超过 200.000 个结果行只用了
但是,如果我从 Web 应用程序运行相同的查询,mariadb-slow.log 会向我显示不同的结果。相同的结果需要 > 4 秒。 什么可能导致这种情况?
# User@Host: _5839b22099d630d5[_5839b22099d630d5] @ localhost [127.0.0.1]
# Thread_id: 685 Schema: _5839b22099d630d5 QC_hit: No
# Query_time: 4.101652 Lock_time: 0.000055 Rows_sent: 226657 Rows_examined: 226657
# Rows_affected: 0
SET timestamp=1596384652;
SELECT item_code, stock_value, name, warehouse
FROM `tabStock Ledger Entry` sle
WHERE posting_date <= '2020-08-02' AND warehouse = 'bom'
ORDER BY posting_date DESC;
用 JSON 解释
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "sle",
"access_type": "range",
"possible_keys": [
"warehouse",
"posting_date",
"posting_sort_index",
"warehouse_2"
],
"key": "warehouse_2",
"key_length": "567",
"used_key_parts": ["warehouse", "posting_date"],
"rows": 126605,
"filtered": 100,
"attached_condition": "sle.warehouse <=> 'bom' and sle.posting_date <= '2020-08-02' and sle.warehouse = 'bom'"
}
}
【问题讨论】:
-
你能检查一下如果你只按两个语句之一订购会发生什么。也许时间戳的创建需要很长时间。为什么不直接按日期、时间排序,而不是将它们传递给时间戳函数?
-
哪个版本的 MariaDB?
-
10.2.31-MariaDB-1:10.2.31+m
-
将 226657 行铲出门需要 4 秒。客户会用这么多东西做什么? Rows_examined 是花费总时间的一个重要因素。