首页 > 解决方案 > 如何练习大型 SQL Server 索引或分区问题进行面试?

问题描述

对不起,如果这应该是关于职业或工作场所堆栈交换的。它似乎跨越了界限,所以我不知道该放哪一个。

我即将在一家非常理想的公司进行现场技术面试,但这超出了我目前的技能范围。我是高级 Java 人。这个机会不仅跨越到 .NET 堆栈,而且在一个团队中,他们正在对大型 SQL Server 数据库(可能是数十亿行?)进行多线程查询。

有一次,经理说,“我不想浪费你的时间,但如果你愿意,我可以带你进来……”我很惊讶他没有简单地说,对不起,你没有我们需要的技能。我完全脱离了我的元素。在我的职业生涯中,我做过各种数量和深度的 SQL,但没有达到这个规模,而且最近也没有(最近做了更多的 noSQL,比如 Mongo 和 Amazon Dynamo)。但我正在经历它,因为我正在这个地方寻找任何人(并且讨厌目前的工作,并且有时间准备)。

我已经完成了 SQL Server 技术面试问题之类的基本搜索,并且已经开始研究它们,但这并不能代替实际经验。有没有办法用一些大的公共数据来设置我自己的大型 SQL Server 来练习其中的一些?

标签: .netsql-servermultithreadingbigdata

解决方案


我只是想表明我将从哪里开始。

  1. 创建没有 VARCHAR(MAX) 的表以避免性能问题

    CREATE TABLE Person 
    (
    PersonID INT NOT NULL,
    FirstName VARCHAR(50),
    LastName VARCHAR(50),
    Address VARCHAR(50)
    )
    
  2. 插入一些测试数据。该表在加载数据之前不应有任何索引,因为索引会降低插入性能

    DECLARE @RunDate datetime
    SET @RunDate=GETDATE()
    
    DECLARE @values TABLE (DataValue int, RandValue INT)
    
    ;WITH mycte AS
    (
    SELECT 1 DataValue
    UNION all
    SELECT DataValue + 1
    FROM mycte 
    WHERE DataValue + 1 <= 1000000
    )
    INSERT INTO Person(PersonID, FirstName, LastName, Address)
    SELECT 
    DataValue
    , 'FirstName' + CAST(DataValue AS VARCHAR(10)) 
    , 'LastName' + CAST(DataValue AS VARCHAR(10)) 
    , 'Address' + CAST(DataValue AS VARCHAR(10)) 
    FROM mycte m 
    OPTION (MAXRECURSION 0)
    
  3. 然后创建索引。

    -- Clustered index
    ALTER TABLE dbo.Person ADD CONSTRAINT PK_PersonID PRIMARY KEY CLUSTERED 
        (PersonID);
    
    CREATE NONCLUSTERED INDEX [IX_Person_FirstName_LastName]
    ON dbo.Person
    (FirstName, LastName) INCLUDE(Address)
    
  4. 练习查询调优。点击Ctrl + MSSMS 查看查询计划。比较查询计划。尝试调整查询Query 2

    -- Query 1 
    SELECT * FROM dbo.Person p
    WHERE p.FirstName = 'FirstName1'
    -- Query 2
    SELECT * FROM dbo.Person p
    WHERE p.Address = 'Address1'
    
  5. 当您进行 I/O 操作时,您应该使用异步操作。所以你需要使用一些ORM。例如,实体框架 在我的经验中,当您使用 IO 时,我还没有找到在 ASP.NET MVC 中使用多线程的理由,因为所有逻辑都在数据库中执行。所以 SQL Server 的优化器自己进行并行化。因此在处理 IO 操作时无需使用多线程。

    public async Task<List<Person>> GetAllPersonsWithName(string personName)
    {            
        return await db.Persons.Where(u => u.FirstName == personName).ToListAsync();
    }
    
  6. 然后尝试异步运行存储过程(如果您使用异步操作,您的团队会很高兴)

    Task<int> firstResult = 
        db.Database.ExecuteSqlCommandAsync("exec FooProcedure @param", 
            new SqlParameter("@param", yourParam));
    Task<int> secondResult = 
        db.Database.ExecuteSqlCommandAsync("exec FooProcedure1 @param1", 
            new SqlParameter("@param1", yourParam1));
    
    await Task.WhenAll(mcResult, dcaiResult);
    
    int fr = firstResult.Result;
    int sr = secondResult.Result;
    
    Console.WriteLine($"Results are fr {fr}, sr {sr} ");
    

C#当您编写和T-SQL编码时,还有一些建议:

  • C# 代码必须是async. 作为async/await保存线程。高性能和可扩展性不能与每个套接字一个线程一起使用。好文章值得阅读。这段代码真的很酷!

  • 此外,如果您未来的团队使用 EntityFramework,则在选择数据时使用方法,而不是添加或更新:.AsNoTracking()

    context.YourTable.AsNoTracking()

  • 尽量避免编写复杂的LINQ to Entities查询。AsEntityFramework可以创建类型为 like 的变量VARCHAR(MAX)。这会降低性能。相反,只需创建用户定义的函数。对于复杂的逻辑使用stored procedures, views, user-defined functions.

  • 尝试调整查询。阅读这篇关于查询调优的文章。另外,做个测试例子,尝试实现index seek操作,找到解决key lookups的方法(避免任何implicit\explicit conversionsinWHERE语句,在index或者include这个列中添加列)。可以在AdventureWorks数据库中进行调整查询。


推荐阅读