AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 13674
Accepted
datagod
datagod
Asked: 2012-02-23 09:04:48 +0800 CST2012-02-23 09:04:48 +0800 CST 2012-02-23 09:04:48 +0800 CST

解析大量字符串的最佳方法是什么?

  • 772

我有一个包含超过 400,000,000 条记录的表,我正在寻找有关如何快速解析它的建议。

TheNameTable
(
  NameID  int primary key,
  TheName varchar(500)
)

名称存储如下:“FirstName,LastName”(不是我的表,只是我必须使用的)

我需要提取一个唯一的姓氏列表。我最初的想法是分批处理表(比如一次 50,000 条记录),使用 NameID 来控制批范围。然后,我将使用 SQL 的内置字符串函数在“,”处断开字符串并保留字符串的右半部分。

right(TheName,charindex('.',reverse(TheName))-1)

我有一种感觉,这仍然需要很长时间。

有没有人有其他想法?

简单地导出数据并在数据库外处理文件是否值得?

我采用的解决方案:

按照建议,我创建了两个计算列。一个用于名字,一个用于姓氏。它们没有持久化,因为我的空间有限。

alter table TheNameTable 
add LastName as substring(TheName, charindex(',',TheName)+1,1000)

alter table TheNameTable 
add FirstName as left(TheName,charindex(',',TheName)-1)

我要求管理员临时增加 RAM,他们将 VM 提高到 32GB。

我创建了一个新表,其中包含 FirstName 和 LastName 列。我在列上放置了一个唯一的复合索引,但指定了 IGNORE_DUP_KEY = ON。

我刚刚插入了前 1,000,000 条记录。它过滤掉了 125,000 个重复项。整个语句运行了 9 秒。

这就是我想要的速度!

sql-server
  • 4 4 个回答
  • 4726 Views

4 个回答

  • Voted
  1. Best Answer
    Darin Strait
    2012-02-23T10:14:06+08:002012-02-23T10:14:06+08:00

    4亿个名字是很多。我在里面吗?;-)

    我的直觉表明,使用子字符串不会比通过 CLR 编写代码慢得多。我是一名 SQL 专家,过去(2000 年或 2005 年)我已经完成了相当多的简单解析,并且我参与了一个非常复杂的解析方案(全球地址) c 并通过 xproc 调用,直到我们发现原型“本机”代码并不比使用 tsql 函数编写的相同代码快。

    如果您想使用 tsql 以外的语言,我建议您在 c# 或 vb.net 中编写 CLR。对于简单的事情,在 CLR 中编写代码并不难。我在不到一个早上的时间里从 newb 变成了几个工作目录和文件实用程序。网上有很多简单的 clr 程序的例子。而且您不必学习任何东西(或安装 Visual Studio)就可以在 tsql 中编写它

    无论如何,您必须至少检查一次桌子。如果你导出,然后解析然后放回不是少量的数据,那是很多时间。你能保证你的来源不会同时改变吗?

    这似乎总是在每个人身上偷偷摸摸:解析的数据会发生什么?它在哪里结束?您是否打算更新该行,也许您的示例中没有显示姓氏和名字列?

    如果你这样做了,并且这些列当前为空或其中的长度为零,你可能会发现更新语句的性能非常糟糕,因为 sql 可能必须拆分页面来存储姓氏。

    换句话说,您的性能问题不是解析,而是存储解析的数据。通常,这比将数据插入另一个表更糟糕。此外,所有这些页面拆分都会使您的表碎片化并导致查询性能下降,这可能会激怒您的 dba,因为他/她必须在(大)表上运行碎片整理过程。

    这是最后一个想法:你真的需要存储解析的数据吗?您可以使用一个即时计算姓氏的计算列吗?如果您需要,这些是可索引的,在某些条件下。另一种方法是公开表列以及“解析的姓氏列”的视图。

    • 6
  2. Ash Burlaczenko
    2012-02-23T09:21:42+08:002012-02-23T09:21:42+08:00

    用另一种语言(例如 c#)编写一个小脚本可能会更快,例如从表中提取所有数据然后对其进行操作。

    然后,您可以对数据执行任何操作,或者将其发送到其他地方,或者使用 BCP 返回数据库。

    • 3
  3. ConcernedOfTunbridgeWells
    2012-02-23T09:43:13+08:002012-02-23T09:43:13+08:00

    如果您可以访问一组 unix shell 实用程序(如果您需要获得在 Windows 上运行的实用程序,请参阅gnu win32TheName ),您可以导出该列并使用 shell 管道处理它,如下所示:

    cut -d, -f2 | sed 's/ //g' | sort | uniq
    

    不过,出口过程将非常昂贵。在 SQL Server 上,您可以使用以下查询创建一个带有姓氏的临时表:

    select distinct rtrim(ltrim (substring (Name, charindex (',', TheName) + 1, 100)))
      into #DistinctSurnames
      from TheNameTable
    

    不管你怎么看,你都准备好进行表扫描了。导出可能比查询上的不同处理更昂贵,因此猜测查询会更快。

    • 3
  4. WernerCD
    2012-02-23T18:15:32+08:002012-02-23T18:15:32+08:00

    我一直在学习很多关于 SQL Server 处理的知识,并认为我会用 Cursor 来尝试一下。我的想法是创建另一个数据库(甚至可能是另一个实例),以便您可以根据需要截断日志,因为这是一个“报告”数据库,并且您希望限制与“实时”数据的交互。

    在我看来,光标将是一个好主意,因为您可以随时进行处理,理论上可以一次性完成。不会太难

    • 将计数字段添加到 LastName 表,例如,对出现的姓名进行计数(姓名、计数)。
    • 添加一个循环计数器,在 100 万次循环后清除事务日志。
    • 添加将名称拆分为单个表的分隔符(LastNameA、LastNameB、... LastNameOther、Invalid)

    Merge 是一个 2008+ 构造,所以如果您创建了另一个实例并链接到 2000/2005(如果您不在 2008+),这将起作用,afaik:

    /*
    USE Master;
    IF EXISTS(SELECT name FROM sys.databases WHERE name = 'Original') DROP Database Original;
    GO
    
    CREATE DATABASE Original;
    GO
    
    USE Original;
    GO
    
    IF OBJECT_ID('TheNameTable','U') is not null DROP Table TheNameTable;
    GO
    Create Table TheNameTable (NameID INT Primary Key Identity, TheName varchar(500));
    GO
    INSERT INTO TheNameTable Values('John, Wayne');
    INSERT INTO TheNameTable Values('Wayne, Berry');
    INSERT INTO TheNameTable Values('Bill, Murray');
    INSERT INTO TheNameTable Values('Elvis, Presley');
    INSERT INTO TheNameTable Values('Lady, Gaga');
    INSERT INTO TheNameTable Values('Latoya, Jackson');
    INSERT INTO TheNameTable Values('Michael, Jackson');
    INSERT INTO TheNameTable Values('Tito, Jackson');
    INSERT INTO TheNameTable Values('Randy, Jackson');
    INSERT INTO TheNameTable Values('Prince');
    GO
    */
    SELECT * FROM TheNameTable;
    
    USE Master;
    IF EXISTS(SELECT name FROM sys.databases WHERE name = 'Reporting') DROP Database Reporting;
    GO
    
    CREATE DATABASE Reporting;
    GO
    ALTER DATABASE Reporting SET RECOVERY SIMPLE;
    GO
    
    USE Reporting;
    GO
    
    IF OBJECT_ID('LastName','U') is not null DROP Table LastName;
    GO
    Create Table LastName (Name varchar(500) PRIMARY KEY);
    GO
    
    DECLARE @TheName varchar(500);
    DECLARE @LastName varchar(500);
    DECLARE LastNameCursor Cursor
    FOR 
    Select TheName
    From Original.dbo.TheNameTable;
    
    Open LastNameCursor;
    
    Fetch NEXT FROM LastNameCursor INTO @TheName;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF (@TheName LIKE '%,%')
        BEGIN
            SET @LastName = right(@TheName,charindex(',',reverse(@TheName))-1);
            MERGE INTO dbo.LastName T
            USING (SELECT @LastName Name) S
                    ON T.Name = S.Name
        --  WHEN MATCHED THEN
        --          Nothing to do here.
            WHEN NOT MATCHED
                    THEN INSERT VALUES (@LastName);
        END
    
        FETCH NEXT FROM LastNameCursor INTO @TheName;
    END
    
    CLOSE LastNameCursor;
    DEALLOCATE LastNameCursor;
    GO
    
    SELECT * FROM Reporting.dbo.LastName;
    GO
    
    • 0

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve