I stopped using RoboForm at version 6.9.
Don't get me wrong... I loved RoboForm. It was almost seamless in it's integration with the browser. I had hundreds of passwords stored and negligible delay. I could generate a new password in a couple of clicks. I even ignored websites that wouldn't work with RoboForm.
But then RoboForm decided that my passwords were their data, to store on their servers. So when Apple or WalMart bought them, then they owned my passwords. Or when Russia or China or Houston hacked them, then I'm pwned.
So now I use KeePass. The browser responsiveness suffers. But my security -- the whole point of passwords -- is my responsibility again.
Sunday, June 3, 2012
Thursday, September 4, 2008
Lazy Loading Can Cause Performance Problems
A customer rushed into LINQ to SQL without fully understanding the consequences, and was having performance problems with their app. The problem: not being cognizant of what Lazy Loading was doing.
So here is a simple example, using the Northwind database.
Suppose you have a DTO like this:
Never mind the
Because now the app is going to the database multiple times. Before the change, he was going to the database once, when evaluating var q in query:
but now the app goes to the database once for the
and the app, unlike this example, was looping thousands of times.
Agreed, the first programmer shouldn't have coded
How should the second programmer have coded his query? Specify the count in the select clause, like this:
Then you only go to the database once.
So here is a simple example, using the Northwind database.
Suppose you have a DTO like this:
public class DTO
{
public string CustomerID { get; set; }
public int OrderID { get; set; }
public DateTime? OrderDate { get; set; }
public int NumItems { get; set; }
public DTO (string customerID, int orderID, DateTime? orderDate, int numItems)
{
CustomerID = customerID;
OrderID = orderID;
OrderDate = orderDate;
NumItems = numItems;
}
public static ICollectionGetDTO(string customerID)
{
ICollectiondtos = new Collection ();
using (NorthwindDataContext context = new NorthwindDataContext())
{
var query = from o in context.Orders
where o.CustomerID == customerID
orderby o.OrderDate descending
select o;
foreach (var q in query) dtos.Add(new DTO(q.CustomerID,
q.OrderID, q.OrderDate, q.Order_Details.Count));
}
return dtos;
}
}
Never mind the
select o
for the moment. Some history: the requirement for NumItems was a change to the original code. A second programmer added the NumItems property, added the numItems parameter to the constructor, and added the q.Order_Details.Count to the foreach statement. Why should that matter?Because now the app is going to the database multiple times. Before the change, he was going to the database once, when evaluating var q in query:
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate],
[t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight],
[t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion],
[t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[CustomerID] = @p0
ORDER BY [t0].[OrderDate] DESC
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [BOLID]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
but now the app goes to the database once for the
var q in query
and once each time in the loop
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate],
[t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight],
[t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion],
[t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[CustomerID] = @p0
ORDER BY [t0].[OrderDate] DESC
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [BOLID]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t0].[Quantity], [t0].[Discount]
FROM [dbo].[Order Details] AS [t0]
WHERE [t0].[OrderID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [10970]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t0].[Quantity], [t0].[Discount]
FROM [dbo].[Order Details] AS [t0]
WHERE [t0].[OrderID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [10801]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t0].[Quantity], [t0].[Discount]
FROM [dbo].[Order Details] AS [t0]
WHERE [t0].[OrderID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [10326]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
and the app, unlike this example, was looping thousands of times.
Agreed, the first programmer shouldn't have coded
select o
-- it's the LINQ equivalent of SQL's SELECT *
. But although he was returning many more columns than he needed to, he only did it once.How should the second programmer have coded his query? Specify the count in the select clause, like this:
var query = from o in context.Orders
where o.CustomerID == customerID
orderby o.OrderDate descending
select new {o.CustomerID, o.OrderID, o.OrderDate,
o.Order_Details.Count};
foreach (var q in query) dtos.Add(new DTO(q.CustomerID,
q.OrderID, q.OrderDate, q.Count));
Then you only go to the database once.
SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[OrderDate], (
SELECT COUNT(*)
FROM [dbo].[Order Details] AS [t1]
WHERE [t1].[OrderID] = [t0].[OrderID]
) AS [Count]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[CustomerID] = @p0
ORDER BY [t0].[OrderDate] DESC
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [BOLID]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
Thursday, August 16, 2007
Debugging Web Services on Your Local Machine
Scenario: Visual Studio 2005, one solution, two projects; one project is your Web Service project, the other your client. IIS is not on your client.
This could eliminate your getting the "System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it" exception in the Reference.cs file.
- Clicking "Properties" of the Web Services project, click the "Web" tab. Change the entry under "Use Visual Studio Development Server" from "Auto-assign Port" to "Specific port".
- Clicking "Set Startup Projects" of the solution, change the entry from "Current selection" to "Multiple startup projects." Change the Action from "None" to "Start."
- Make sure your client project is set up as the Startup Project.
- If you haven't already, add the Web Reference in your client project, choosing "Web Services in this solution."
- Make sure that your dependencies are set so that your client project is dependent upon your Web Services project.
This could eliminate your getting the "System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it" exception in the Reference.cs file.
Monday, May 21, 2007
CruiseControl.NET VSS SSDIR
Switched from a test SourceSafe database to production, which was on a separate machine. The ccnet.config file used to have a line that specified the srcsafe.ini file, saying
I switched it to
ThoughtWorks.CruiseControl.Core.CruiseControlException: Source control operation failed: No VSS database (srcsafe.ini) found. Use the SSDIR environment variable or run netsetup.
I stumbled around for a while, but finally changed the <ssdir> tag to just the directory, removing the srcsafe.ini file, as in
and that got it working.
<ssdir>C:\local\srcsafe.ini</ssdir>
which worked fine.I switched it to
<ssdir>\\remotemach\vssdb\srcsafe.ini</ssdir>
and started getting the messageThoughtWorks.CruiseControl.Core.CruiseControlException: Source control operation failed: No VSS database (srcsafe.ini) found. Use the SSDIR environment variable or run netsetup.
I stumbled around for a while, but finally changed the <ssdir> tag to just the directory, removing the srcsafe.ini file, as in
<ssdir>\\remotemach\vssdb\</ssdir>
and that got it working.
Friday, May 18, 2007
Batch FxCop and Visual Studio's Website Project
Using Continuous Integration, you want to run FxCop against the build. Using Visual Studio's new "Website" project (Rick Strahl has some commentary about it), the aspnet_compiler creates DLLs with random names embedded. This is good, because it's unlikely that that DLL is cached anywhere. But it's bad, because FxCop wants to know what the DLL names are.
There's probably a better way to handle it, but we simply run aspnet_compiler twice: the first time with the -fixednames parameter, running FxCop against that build, then the second time without the -fixednames parameter generating uncached DLLs.
There's probably a better way to handle it, but we simply run aspnet_compiler twice: the first time with the -fixednames parameter, running FxCop against that build, then the second time without the -fixednames parameter generating uncached DLLs.
Monday, May 14, 2007
NAnt String Concatenation
I'm not familiar with Ant, but in NAnt, the plus sign can act as a string concatenation operator, so you can say something like
You can also use the Concat function. Both are documented.
<mkdir dir="${work-dir}\Svcs" if="${not directory::exists(work-dir+'\Svcs')}">
You can also use the Concat function. Both are documented.
Sunday, May 13, 2007
Thunderbird / SpamPal / SSL / STunnel / 2 ISPs
Lots of good info setting up SpamPal with STunnel to communicate with ISPs requiring SSL for email. But recently, my ISP also required SSL, and I was already using the STunnel connection for Google.
Not a problem. Just make two entries in your stunnel.conf file, like so:
In Thunderbird, the "User Name" in the Server Settings of Account Settings is My.Name@gmail.com@localhost:1110 for the GMail account, and My.Name@myisp.com@localhost:1111 for the ISP.
Not a problem. Just make two entries in your stunnel.conf file, like so:
; incoming email from GMail
[pop3gm]
accept = 127.0.0.1:1110
connect = pop.gmail.com:995
; incoming email from ISP
[pop3is]
accept = 127.0.0.1:1111
connect = pop.myisp.com:995
In Thunderbird, the "User Name" in the Server Settings of Account Settings is My.Name@gmail.com@localhost:1110 for the GMail account, and My.Name@myisp.com@localhost:1111 for the ISP.
Subscribe to:
Posts (Atom)