简体   繁体   English

C#:Inner Join 4表SQL Server

[英]C#: Inner Join 4 tables SQL Server

I am joining 4 tables in one SQL statement that reads data into objects and fill a gridview as well. 我在一个SQL语句中加入了4个表,这些表将数据读入对象并填充gridview。

My question : Is this a good practice ? 我的问题 :这是一个好习惯吗? does it have any side effects like performance when reading from the database? 从数据库中读取时有没有像性能这样的副作用? if so please provide me with some tips in improving it. 如果是这样,请提供一些改进建议。

protected void OrdersGridView_SelectedIndexChanged(object sender, EventArgs e)
{
    string OID = OrdersGridView.SelectedRow.Cells[0].Text;
    OrderIDlbl.Text = "Order# " + OID;

    using (SqlConnection con = new SqlConnection(cData.CS))
    {
        con.Open();
        {
            string sql = "select o.*, c.*, oi.*, p.* from Orders as o INNER JOIN Customers as c ON o.CustID = c.CustomerID INNER JOIN OrderItems as oi ON o.OrderID = oi.InvoiceID INNER JOIN Products as p ON p.PartNumber = oi.PartNumb where OrderID ='" + OID + "'";

            SqlCommand myCommand = new SqlCommand(sql, con);
            myCommand.CommandTimeout = 15;
            myCommand.CommandType = CommandType.Text;

            using (SqlDataReader myReader = myCommand.ExecuteReader())
            {
                while (myReader.Read())
                {
                    passid.Text = (myReader["CustID"].ToString());
                    TermsDropdown.Value = (myReader["PaymentTerms"].ToString());
                    PaymentDate.Value = ((DateTime)myReader["PaymentDate"]).ToString("MMMM dd, yyyy");
                    OrderDate.Value = ((DateTime)myReader["OrderDate"]).ToString("MMMM dd, yyyy");
                    SalesRep.Value = (myReader["SalesRep"].ToString());
                    comenttxtbox.Value = (myReader["Comments"].ToString());
                    Discountlbl.Text = "Discount: " + (myReader["Discount"].ToString() + " AED");
                    Totallbl.Text = "Total: " + (myReader["Total"].ToString() + " AED");
                    Statuslbl.Text = (myReader["OrderStatus"].ToString());
                    SelectCustomertxtbox.Value = (myReader["Company"].ToString());
                    Name.Text = "Name: " + (myReader["FName"].ToString()) + " " + (myReader["LName"].ToString());
                    Phone.Text = "Phone: " + (myReader["Phone"].ToString());
                    Mail.Text = "Mail: " + (myReader["Personal_Email"].ToString());
                }
            }

            DataTable dt = new DataTable();

            using (SqlDataAdapter da = new SqlDataAdapter(myCommand))
            {
                da.Fill(dt);

                OrderItemsGridview.DataSource = dt;
                OrderItemsGridview.EmptyDataText = "No Items";
                OrderItemsGridview.DataBind();
            }
        }
    }
}

订购POPUP

I wouldn't necessarily say it is a bad practice to do joins, however you should definitely get rid of the alias.* pattern that is emerging in your queries. 我不一定会说这是一个不好的做法,但你绝对应该摆脱你的查询中出现的别名。*模式。 Not explicitly selecting which columns you need is a bad practice in code. 没有明确选择您需要的列是代码中的错误做法。

As for the join, often it is the only way if you do not have control over the database design. 至于连接,如果您无法控制数据库设计,通常它是唯一的方法。 However, you could greatly simplify your in-code SQL query by creating a view which does those joins for you. 但是,您可以通过创建一个为您提供这些连接的视图来大大简化您的代码内SQL查询。 I would, however, question whether or not an INNER JOIN is what you actually want. 但是,我会质疑INNER JOIN是否是您真正想要的。 Keep in mind an inner join only shows results that contain a match on both sides of the join. 请记住,内部联接仅显示在联接两侧包含匹配项的结果。

In your particular case, I recommend separating the queries for the order information and the order items themselves. 在您的特定情况下,我建议将订单信息和订单项本身的查询分开。 You're adding redundant information by including the order info on every order item. 您通过在每个订单商品上添加订单信息来添加冗余信息。 Also, whenever your query requires outside input, make sure to use a parameterized query: 此外,只要您的查询需要外部输入,请确保使用参数化查询:

myCommand.CommandText = "select o.Date, o.Title, o.Id from Orders where Id = @Id";
myCommand.Parameters.Add("@Id", SqlDbType.Int);
myCommand.Parameters["@Id"].Value = 3;

Don't forget to get rid of the alias.* stuff in favor of explicitly selecting your columns. 不要忘记删除别名。*有利于明确选择列的东西。

I would suggest to create a stored procedure in the database with the argument as Order ID. 我建议在数据库中创建一个存储过程,其参数为Order ID。 Then call the stored procedure from the .net instead the direct calling the SQL. 然后从.net调用存储过程而不是直接调用SQL。 This has the below advantages 这具有以下优点

  1. Removes the SQL Injection security problem. 删除SQL注入安全问题。
  2. SQL caches the query plan and executes faster the next time you process it, rather than the adhoc query you are firing. SQL会缓存查询计划,并在下次处理时执行得更快,而不是您正在触发的adhoc查询。

Only include the necessary columns in your data. 仅在数据中包含必要的列。 You're pulling a lot of extra data that you don't need, which is created extra server & network overhead, and will absolutely make things slower. 您正在提取许多您不需要的额外数据,这会产生额外的服务器和网络开销,并且绝对会让事情变得更慢。

Also, you need to use a SqlParameter for any parameters. 此外,您需要为任何参数使用SqlParameter Your SQL is subject to sql injection. 您的SQL受sql注入。

string sql = "select <only columns you need> from Orders as o INNER JOIN Customers as c ON o.CustID = c.CustomerID INNER JOIN OrderItems as oi ON o.OrderID = oi.InvoiceID INNER JOIN Products as p ON p.PartNumber = oi.PartNumb where OrderID ='@OrderId";
            SqlCommand myCommand = new SqlCommand(sql, con);
            myCommand.CommandTimeout = 15;
            myCommand.CommandType = CommandType.Text;
            myCommand.Parameters.AddWithValue("@OrderId", oid);

It depends on how you query the data. 这取决于您查询数据的方式。 If its only simple SELECT ... FROM ... WHERE ID = X then it is totally fine to do. 如果它只是简单的SELECT ... FROM ... WHERE ID = X那么它完全没问题。

But there are cases which such join is going to cause significant performance degrade. 但是有些情况下这种连接会导致性能显着下降。 Lets say you did something like 让我们说你做了类似的事情

SELECT TOP 10 * FROM Table1 INNER JOIN Table2 ON..  
INNER JOIN Table3 ON .. 
INNER JOIN Table4 ON.. 
WHERE Table1.Column1 = 1 AND 
      Table2.Column1 = 2 AND 
      Table3.Column1 = 3 AND 
      Table4.Column1 = 4 
ORDER BY Table1.Column1, Table2.Column1, Table3.Column1, Table4.Column1

This is very unlikely to happen but if you ever come across a case like this, Sql is likely to do a full table scan since indexes can only include columns in its own table but the order by included columns in all 4 tables so does the where clause. 这种情况不太可能发生,但是如果遇到这样的情况,Sql很可能会进行全表扫描,因为索引只能在自己的表中包含列,但是所有4个表中的包含列的顺序也是如此条款。

In order to solve such problem you could use a materialized views which you can add indexes to cover all columns. 为了解决此类问题,您可以使用物化视图,您可以添加索引以覆盖所有列。 But before you need something complicated like this 4 joins is fine. 但是在你需要像这样的4个连接之前就可以了。

In addition to what Jakotheshadows has answered, before you make the changes as per his suggestion and getting the data in multiple calls (separate queries) ask yourself these questions: 除了Jakotheshadows所回答的内容之外,在根据他的建议进行更改并在多个调用中获取数据(单独查询)之前,请问自己以下问题:

What is more important for you? 什么对你更重要?

  1. Saving the amount of redundant data you are getting? 保存您获得的冗余数据量? If yes, then proceed with his suggestion. 如果是,那么继续他的建议。
  2. Is speed more important? 速度更重要吗? If yes, then keep the joins but follow Jakotheshadows's advice and use parameters and remove the aliases etc. 如果是,那么保持连接,但遵循Jakotheshadows的建议并使用参数并删除别名等。

If you get the data in one shot, like you are with joins, it means one trip to the database but more redundant data. 如果您一次性获取数据,就像您使用连接一样,这意味着一次访问数据库,但更多的冗余数据。 If you do separate queries, it is more than 1 trip (1 trip per query) so it can take longer. 如果您进行单独的查询,则超过1次旅行(每次查询1次),因此可能需要更长时间。 So make an informative decision. 所以做出一个信息丰富的决定。

In simple words, if you are going grocery shopping do you want to get everything in one shot (heavier trip) or make more trips but make them lighter trips. 简单来说,如果你去杂货店购物,你想要一次性(重旅行)获得所有东西,或者做更多的旅行,但要让它们更轻松。 (Though this grocery example does not have redundancy but you get the point...) (虽然这个杂货店的例子没有冗余,但你明白了......)

Keep in mind that performance (speed) should not be your concern until it has become a bottleneck. 请记住,性能(速度)不应成为您关注的问题,直到它成为瓶颈。 But nonetheless, it is good that you know this. 但是,你知道这一点很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM