Tales of arise – super quick review

Tales of Arise Characters and Party Members

The good

The character designs are pretty good. With a lot of JPRG character designs are basically fan service, to a point it’s even ridiculous to look at (Looking at you, Xenoblade Chronicles 2), the characters from Tales of Arise are pretty great (saved some small parts, like, um, uh, the back of Kisara).

The game looks good – it is not breaking any record, but gorgeous in its own rights.

The bad

Tales has always been a budget series, and while Tales of arise might have a bigger budget than previous entries, it is still not an AAA production. And that shows in places. You see pretty repetitive enemies from place to place. A different color and a new name, and you’re done. This also clear that the game has more loading screens than it should, even with the current gen (Xbox Series X and PS5) versions. This is somewhat understandable as they share same design with previous gen consoles, but it was quite sad to see the limitations.

The voice acting is a hit or miss, i.e. inconsistent. Some actors sounds great and convincing, some, not so much.

Repetitive enemies designs. New area = almost same enemies with different colors.

Performance on boss battles – especially after Dohalim suffer badly. This was not covered by Digital Foundry analysis here, but trust me, I’ve seen it with my own eyes (And suffers from it)

The Ugly

It is one of the worst, if not the worst game when it comes to stability. And I played Witcher 3: The Wild Hunt at release on PS4, and XCOM 2 both on PS4 and Xbox Series X, that says something about it. I played (or rather, am playing) the game on Xbox Series X, and it crashes in almost every session. It does not work with Quick Resume (i.e. it should be disabled).

Mini annoyances

There are upgraded versions of equipment, but if a character is equipping that base version, it can’t be upgraded! You have to unequip that then craft the upgrade. Why?

The hidden gotcha with IObjectInstanceCache

It’s not a secret that cache is one of the most, if not the most, important factors to their website performance. Yes cache is great, and if you are using Optimizely Content/Commerce Cloud, you should be using ISynchronizedObjectInstanceCache to cache your objects whenever possible.

But caching is not easy. Or rather, the cache invalidation is not easy.

To ensure that you have effective caching strategy, it’s important that you have cache dependencies, i.e. In principles, there are two types of dependencies:

  • Master keys. This is to control a entire cache “segment”. For example, you could have one master key for the prices. If you needs to invalidate the entire price cache, just remove the master key and you’re done.
  • Dependency keys. This is to tell cache system that your cache item depends on this or that object. If this or that object is invalidated, your cache item will be invalidated automatically. This is particularly useful if you do not control this or that object.

ISynchronizedObjectInstanceCache allows you to control the cache dependencies by CacheEvictionPolicy . There are a few ways to construct an instance of CacheEvictionPolicy, from if the cache expiration will be absolute (i.e. it will be invalidated after a fixed amount of time), or sliding (i.e. if it is accessed, its expiration will be renewed), to if your cache will be dependent on one or more master keys, and/or one or more dependency keys, like this

   
        /// <summary>
        /// Initializes a new instance of the <see cref="CacheEvictionPolicy"/> class.
        /// </summary>
        /// <param name="cacheKeys">The dependencies to other cached items, idetified by their keys.</param>
        public CacheEvictionPolicy(IEnumerable<string> cacheKeys)

        /// <summary>
        /// Initializes a new instance of the <see cref="CacheEvictionPolicy"/> class.
        /// </summary>
        /// <param name="cacheKeys">The dependencies to other cached items, idetified by their keys.</param>
        /// <param name="masterKeys">The master keys that we depend upon.</param>
        public CacheEvictionPolicy(IEnumerable<string> cacheKeys, IEnumerable<string> masterKeys)

The constructors that takes master keys and dependency keys look pretty the same, but there is an important difference/caveat here: if there is no dependency key already existing in cache, the cache item you are inserting will be invalidated (i.e. removed from cache) immediately. (For master keys, the framework will automatically add an empty object (if none existed) for you.)

That will be some unpleasant surprise – everything seems to be working fine, no error whatsoever. But, if you look closely, your code seems to be hitting database more than it should. But other than that, your website performance is silently suffering (sometimes, not “silently”)

This is an easy mistake to make – I did once myself (albeit long ago) in an important catalog content cache path. And I saw some very experienced developers made the same mistake as well (At this point you might wonder if the API itself is to blame)

Take away:

  • Make sure you are using the right constructor when you construct an instance of CacheEvictionPolicy . Are you sure that the cache keys you are going to depend on, actually exist?

In newer version of CMS, there would be a warning in log if the cache is invalidated immediately, however, it could be missed, unless you are actively looking for it.

Note that this behavior is the same with ISynchronizedObjectInstanceCache as it extends IObjectInstanceCache.

Lelit Elizabeth v3 – 2 months impression (super short review)

First of all, if you are looking to buy Lelit Elizabeth, check out the detailed review from David Corbey. It is probably the best review on the machine. He also wrote very good information regarding setting, and maintaining the machine, so check it out.

Out of the box, the Elizabeth looks much better than in photos. I must admit, the photos do not do its justice – it looks rather dull in those. While it is certainly not the best looking espresso machine (to my taste at least, I think the one with E61 group looks more compelling), it definitely looks good.

Next to the machine it is going to replace

Coming from the popular Sage (Breville) Barista Pro, there are a few things that impress/surprise me (of course this is an unfair comparison. When you spend 3x more money on a new machine + a grinder, you would definitely not want to get “marginally better”):

  • The actual stainless steel construction is very, very nice. It feels much more solid than the fake stainless steel look from the Barista Pro. The machine is well made, probably not the best built machine around, but you know it will last you a long time.
  • It takes really long time to heat up, about 20 minutes. Compared to Barista Pro, it was a bummer at first, because you could pull your first shot almost instantaneously with the Pro as the machine is ready after 3s. But that is a lie. For the Barista Pro, the machine allows you to pull shots, but with the cost of temperature stability. I learned the hard way that most of the shots with Barista Pro is severely under temperature, resulting in extreme sour taste, and it was very hard to adjust – you have like 5 levels for temperature, ranging from 90*C to 98*C, so about 2*C each. If the machine can reach that desired temperature or not, is another question. I only realize that once I switched to Elizabeth. The portafilter is actually hot (and very uncomfortable to touch to steel part). On Barista Pro however, it is only lukewarm, even if I pulled a few empty shots before hand. Furthermore, with Elizabeth, I can set the brewing water to whatever temp I like (or half the degree if I switch to F instead of C), so I can comfortably brew light, medium or dark roast the way they are meant to be brewed.

The flow is now so, so much easier and smoother and I had with the Sage Barista Pro.

Buying accessories is also now easier and cheaper – I could easily find branded, quality accessories for reasonable prices. They might be still expensive, but I feel the price is justified for the the quality.

But no machine is perfect, so is Elizabeth, there are a few downsides

The biggest one, to me at least, is that the water tank is pretty hard to refill, as I put my machine under the kitchen cabinet, so I have a few little space left. I need to either move it out, or use a gooseneck kettle to refill. I went with the latter approach and it works quite well.

Another bummer is that there is lack of a real tamper included in the package. Lacking of the milk jug is somewhat acceptable, but tamper? I bought a nice one from Motta (wish I chose the 58.55mm version instead), but I wish they included one by default. Of course, this one is an easy one to fix.

In the end, I’m happy with my Elizabeth, and I feel happy and excited to use it every day. My only regret is that I didn’t step up to Bianca – heard great things about it. But well, it exceeded my budget at that point by a large margin, I’ll have to wait.

Meanwhile, Lelit Elizabeth will serve me well for a long, long time.

Debugging a memory dump for .net 5

You would need to install Windbg Preview from Windows Store

Get it from Get WinDbg Preview – Microsoft Store . If you use the ordinary Windbg that comes wint Windows SDK, this is what you get from trying to open it

WinDbg:10.0.19041.685 AMD64

Could not find the C:\Users\vimvq\Downloads\core_20211102_090430.dmp Dump File, Win32 error 0n87

The parameter is incorrect.

You also need to install .NET 5 version of sos.

dotnet tool install --global dotnet-sos

and once you used Windbg Preview to open the memory dump, run this command to load it:

.load C:\Users\<your user name>\.dotnet\sos\sos.dll

And now you can start debugging as usual

Coffee roasters in Sweden – a review

If you are serious about Espresso quality, you know you must buy from a specialty roaster – not from the super market. You will pay more premium price, at least 300kr per kg, and easily up to 500kr per kilo or more, compare to around 100-150kr per kg from super market. In return, you get:

  • The obvious better coffee quality. Most if not all decent roasters only roast specialty coffee, meaning they not only taste good, they have minimal defects, especially small rocks. A bad bean will only ruins one cup, at most. But a pebble can destroy your precious coffee grinder. Your grinder will thank you for the uniformity of specialty coffee beans you buy from roasters.
  • Much better freshness. Most, if not all coffees from super market only have “expired date”, not “roast date”. You can probably guess the roast date by subtracting expired date by 24 months and the most fresh one I could find, was two months old. At this point the coffee already started degrading in quality. In contrast, when I buy from roaster, it is always less than 1 week from roast date, which is clearly printed on the bag. As a rule of thumb, you should finish your coffee in less than 8 weeks from roast date.
  • Much better roasted. Most coffee from super market is roasted with super hot air (800*c) in very short amount of time. This allows the roaster to roast ton after ton, but with the cost of coffee flavor. Specialty coffees are often roasted in much smaller batches, an a longer time, for the flavor can develop properly.
  • Traceability. You only know coffee from super market by their country origin, and that’s it. But for specialty coffee, you will know the region which produced the coffee, and in many cases, even the farm that produced it.
  • Last but not least, support for local businesses. Specialty roasters are small businesses in your city, or even area. Buying from them means you support your local economy. Many roasters also have direct trade with the coffee farms, which means you give more directly support those famers. Most farms that grow specialty coffee also follow practices regarding sustainability (and due to high price of specialty coffee, they can sustain their business with considerable smaller farms). If you care about sustainability and people likelihood, buying from roasters is a better way to support that.

What to look for from Coffee roasters

A coffee bean bag with one way valve is a must (In case you didn’t know, newly roasted coffee bean will release CO2, and that valve is important to let the CO2 out – but not let the air in) . Best if it is resealable. otherwise you would have to move the bean to an airtight container to keep them fresh for longer. Also, buy coffee beans if you can. Ground coffee starts losing their aroma and flavor just 30 minutes after grinding. Airtight container can only slow that down a little bit.

All of the roasters below have good coffees – the beans have consistent color, size and shape. My machines, techniques and taste are not at the level I can distinct each flavor, so I will focus on the services instead.

StockholmRoast (Stockholm Roast – The House of Roasting)

They offers good prices, but no subscription. They ship through DHL to the service point, with free shipping, which is nice, but not the best (compared to other options below)

The bags are well packaged, so you get proper protection of your precious coffee beans. But they also glue a plastic bag on the package (for the shipping information and the receipt), which is quite tiresome to remove for proper recycling.

They also offer better price for 1kg bag, compared to 4 bags of 250. While this is somewhat understandable from a commercial perspective, it means it’s harder to keep your coffee fresh, if you want to save some money. They probably should offer 500gr bag.

Another minus, I don’t recall their bag is resealable. Also the ink on the bag could easily get into you hands, especially if they are a little wet. They are, however, not very easy to wash off.

None of those things are critical, but they would be very nice to be fixed!

LYKKE KAFFEGÅRDAR Nyrostat kaffe | Direkt från gården hem till dig | Lykke Kaffegårdar (lykkegardar.se)

Lykke offers subscriptions, with 10% discount, which is good. Importantly, they ship directly to your mailbox. Order, and in one day or two, you find your favorite coffee bags in your mailbox. Convenient, huh?

You can easily manage subscriptions, including changing it, skip one delivery, or cancel it, which is a huge plus.

Their bag design is beautiful, and I absolutely like it. To make things better, they even included 2 bags of tea in my first shipment – a very good way to advertise.

Their espresso range, however, is quite limited. There is only one Bam! that is dedicated for espresso. Wish they offer more choices.

UPDATE: I bought 2 bags of BAM! from them due to their Black Friday sales, and were sent ones which were roasted on October 28th, which means more than 1 month when they arrived. I was disappointed, and sent them a letter. They apologized and offered a 30% coupon for my next order. While receiving one month old coffee bags is no fun, I think the way they handled it was nice. I took the offer.

Kafferosterietkoppar Upptäck vårt nyrostade kaffe | Kafferosteriet Koppar

They offer subscriptions as well, and with 20 SEK discount per bag, which is very nice. However, to change the subscription, you need to email them directly. It’s OK-ish, but I would definitely prefer the Lykke approach.

They also ship directly to mailbox, and their shipping was very fast. I ordered on Wednesday, and two of the bags appeared in my mail box on Thursday. I don’t know if they forgot, or intentionally did not send a notification email, but that was a nice surprise.

One incident with my first purchase: Out of two bags is almost empty (there were like, 30 coffee beans inside them). I mailed them to let they know, and they were happy to ship a replacement to me. In the end, everything is resolved quick and easy, but I’d hope they did have a bit more of quality control for their coffee bag.

Standout coffee https://www.standoutcoffee.com/

Their subscription is 25e (yes, euro, equivalent to about 260kr) for 100gr of coffee, or 2600kr per kilo. The reason for such high price is because it’s “Gesha village”, the most expensive coffee in the world, and they offer worldwide free shipping.

2600kr per kilo is unfortunately way too high for what I can pay for coffee, and with 100gr you might get 1-2 cup of good espresso out of it (considering you have to dial in), so thanks, but no thanks.

Drop Coffee

Apparently they are the most popular in Sweden, so I should try them out soon. They are transparent about their FOB price, which is nice. I was hesitant about their Google reviews (“only” 4.3 on 5.0, so quite lower than other roasters in this list), but it turned out it has to do with their coffee shops (which should be affected by many other things) than their actual roasting business.

Pouring coffee roastery (hallakafferosteri.com)

This is my favorite now. They offer coffees at very good price – especially if you buy in batch (5 or 10 bags of 500gr), and they usually have 10 or 15% off coupon. I buy with a few friends, and we split the bag – and I end up with around 250kr/kg (2x500gr bag), and sometimes even only 220kr. They do ship free to service point for order more than 499kr.

I can’t notice a difference between their coffee and other roasters, so I’m happy with that setup, for now.

Sage/Breville Barista Pro review

This is a super short review of this fairly popular espresso machine. I bought this last year, despite a lot of arguments from my wife. She even threatened to throw it out if I bought. I did. And now she demands latte/cappuccino every day!

My budget was pretty limited at that point, so other decent options (HX or even dual boiler machines) are out of reach. Barista Pro fits in my budget (and kitchen), and when Amazon had a very good discount on them, I pulled the trigger.

I was happy.

When it was new

Don’t laugh.

Pros:

Sage/Breville is feature oriented, and when you open the box, you have everything you need to get going: a milk jug, a 54mm portafilter with 4 different baskets (2 double shots (1 pressurized, 1 non pressurized), 2 single shot), and of course, a grinder built-in. If you are new, this is hugely important. Some sellers do not include the milk jug, or even tamper (looking at you, Lelit!), and it’s bad that you are excited to open your new fancy espresso machine and realize you can’t make a decent cappuccino due to lacking equipment. The UI is intuitive and easy to work with. Once you understand the basics, using the machine, UX wise, is simple and easy.

The flow is well defined, and smooth – you take the portafilter, put it in the holder and click – the grinder grinds coffee for you, in the fineness you chose and the time you pick. Then you take the tamper (attached to the machine using a magnet, a pretty smart design), tamp it, put it in the head, place your cup, and press a button. It is the convenience you are paying for.

Cons:

Once you open the box, you quickly realize this machine is not built to last. It’s a thin layer of stainless steel outside of plastic. Build quality is … fine, but don’t expect the same quality as Italy-made machine. It’s been reported that while Sage/Breville service is very good during warranty, but one you are out of warranty, you have to pay hefty fee for repairs, because they just break down. And repair usually means “replace”.

The machine is advertised as “3s start up time”. You press a button, and the machine is ready. Truth is, however, if you want to get better shots, you need to wait for at least 10m, and flush 1 or 2 cup first. With the empty portafilter inserted, press the double shots button, and let the hot water flows through it. It warms up the head, the portafilter, and make sure you get stabilized temperature in the boiler. Otherwise, your cups will be incredibly sour. Or some times, both sour of bitter!

The machine overall is quite noisy, both the grinder and the pump. it’s not a big deal until you have tried quieter machines. This is even more true when you have empty grinder, it sounds like it gonna break (it is fine to grind in a short amount of time, mind you)

Another downside is that this uses a 54mm portafilter. The portafilter itself is fine, well made and solid, but after a while, you will want to try out new things, like bottomless portafilter. But this is when you realize you are left with either options: 1. buy cheap no brand products from China or 2. absurdly expensive or 3. both. Should it come with a 58mm portafilter which is the “industry standard”, you will have more options from reputable brands, at reasonable prices.

The built-in grinder is merely adequate, it’s step conical burr grinder (some says it’s actual stepless, but you will need some “tricks” for that). You will be able to grind espresso with it, but not with the fineness adjustment needed to extract the best out of your coffee. Whenever you can, upgrade to a good espresso grinder would make a huge difference in your espresso. (Note: a good espresso grinder can easily cost $400 or more!). Also, cleaning it is not the easiest task – it’s doable, but requires additional tools (like a vacuum cleaner) to do it properly.

It’s messy to grind a double shot (18-20gr), because some coffee ground will be left on the portafilter holder, or on the drip tray. Yes you can use a dosing cup, or a funnel, but you will, once again, agonize the limited options of a 54mm portafilter.

So so

The included tamper is “serviceable”. It can be tucked in which is need, and it does it job. But I’d suggest to buy a nice, ergonomic tamper as soon as you can. It’ll make your experience much more enjoyable.

The steam wand is ok, but it is on the weak side, and it produces wetter steam than I would like. It is enough to froth the included milk jug, but if you want to use a bigger jug (so you can make 2 cappuccinos or 1 big latte in 1 go), it’ll not powerful enough.

The included milk jug is OK. Good ergonomic, but the wall is a bit too thin, so it gets hot very quickly. I had hard time holding it when it reaches 55*C. In comparison, my Motta one is only fairly warm even when the milk reaches 60*C (that is however not the perfect thing)

Summary

In the end, Barista Pro is a well rounded, full featured espresso machine. It’s a budget/entry one, capable of making good shots. You have everything you need to start going, but it also does not really excel in neither brewing, nor steaming. Once you horned your skill, upgrading to a better grinder, and a better machine 58mm portafilter will be a big step.

If you want to learn and can spend, of course.

How to spot Facebook Marketplace scams

With the pandemic going for more than 1 year (And still no end in sight), shipping has become a popular option for shopping on Facebook Marketplace. And that’s why scamming skyrocketed. To make the matters worse, Facebook provides little to no shopper protection. Your safety is yours to care about. So how to spot and stay away from scam, beside of other health safety procedures?

If a deal seems to be too good to be true, it is likely is. At this point of writing, PlayStation 5 is most frequently scammed. Anything which is less than 5500 SEK for the standard edition is suspicious. Scalpers who sell high demand product at much higher price than MSRP are another issue, but they are not mutually exclusive. A scammer can try to sell at higher price to make it more “authentic”, but most will try to lure more unsuspecting buyers by low prices.

Photos with low quality are another red flag. It is likely that the seller did not take the photos himself/herself but download from other listing, then upload again. Every time you upload photos to Facebook they reduce the quality a bit to reduce size. Do that a few times and you will notice the artifacts in the photo. If the photo is blurry or pixeled, take that as a warning.

Commerce profile too new: anything newer than 2019 should be questionable. Especially someone with very few friends. Check their profile if you think they are an actual person behind it.

Only offer shipping is another red flag. While some authentic sellers would prefer less contact, it is uncommon. Shipping means you have to Swish (a quick money transfer method in Sweden) before hand, and that means you have no guarantee once you did. If you Swish

Also, check if that seller is selling multiple items, and for each item, a new location is listed. That means the seller is trying to scam you into thinking he/she is far away, so shipping is required.

An example of a scammer

My not very proud experience is that I was scammed myself. I was browsing the MarketPlace, and saw a game (Ratchet & Clank PS5), for a very good price (250kr compared to normally 450-500kr or even more, because the game was new). Contacted the seller, he was responsive, and even offered 50:50 split on shipping cost. I checked his profile, everything seems to check out, so I took the bait. Swish-ed him 270kr. Waited for a few days. The game never came. Ask him if he shipped it, he said yes. Waited for a few days more and asked him what would he do. He never replied. Only a few days later, another buyer reported him for scamming. Same tactic, only this time he admitted to that buyer he never sent the game (a different one), and promised to refund the money. He never did.

Deep down, I wanted him to not be scammer. I even felt a bit sorry for him. What state would he be in, so he has to scam over that small amount of money. Only after a while, I realized he did it systematically. He scams that amount so most people will just accept it and move on. Even if they report him to the police (as the said buyer did), they will likely not do anything about it. He gets away with scamming multiple people like that.

Facebook protection for buyers is a joke. The most you can do is to report the listing as Scam, and they still do nothing about it. So better be cautious and protect yourself.

A super short review of XBox One X

I have been a PS4-fan (if I can call myself so) since the day I bought the original PS4 to play Dragon Age: Inquisition. At that point, PS4 is the clearly better choice than XBox One: smaller without a separate power adapter, 50% more powerful (1.84TFLOPS vs 1.23 TFLOPS), simpler policies to share/resell game, etc etc.

I even liked XBox One X when it was announced, it checks almost all the boxes, except for, well, games and price, so I gave it a pass, especially when I got a PS4 Pro from a colleague at a very good price. This genre, PS4 has won for many reasons, one of that is it has a excellent line of exclusive.

Why not all three of them? Why choose side?

And I remain faithful until the day Elgiganten – a big electronic retailer in Sweden sells Xbox One X with Fallout 76 bundle at an unbeatable price (cheaper than Xbox One X selling alone, so the game actually reduces the price of the bundle!). I talked to myself – why not, if I don’t like it I can just return (it’s turned out that the game is digital, so I won’t be able to return. But I like it in the end so I decided to keep it. I find myself playing Apex Legends every night now, and I’m happy with it)

I won’t play Fallout 76, but this is cheaper than the Xbox One X alone, thanks to it.

The good

A marvel of engineering. It’s significantly more powerful than my PS4 Pro, yet it is just the same size and is even more quiet.

Incredible value if you think about Game Pass. Bunch of good games at a very low price, especially when you use the promotions that happen all the time. I spent about 30 SEK (less than 4 USD) for 3 months of that.

The controller battery lasts me weeks, and it takes only 1 minute or so to replace the battery.

A new generation of gamers!

Games that are optimized for X run exceptionally well. Forza Horizon 4, Red Dead Redemption 2, just to name a few.

Xbox and Xbox 360 games backward compatibility.

UHD Blu-ray player.

The bad

The UI is a mess. I complained about how HBO UI is a mess . But I think XBox One UI is on par in term of terrible.

The ugly

The Blu-ray player that refuses to play my UHD bluray, 9 out of 10 times.

I will have to re-buy many games to get the advantage of native 4K.

Fixing ASP.NET Membership performance – part 1

Even though it is not the best identity management system in the .NET world, ASP.NET Membership provider is still fairly widely used, especially for systems that have been running for quite long time with a significant amount of users: migrating to a better system like AspNetIdentity does not comes cheap. However, built from early days of ASP.NET mean Membership provider has numerous significant limitations: beside the “architecture” problems, it also has limited performance. Depends on who you ask, the ultimate “maximum” number of customers that ASP.NET membership provider can handle ranges from 30.000 to 750.000. That does not sound great. Today if you start a new project, you should be probably better off with AspNetIdentity or some other solutions, but if your website is using ASP.NET membership provider and there is currently no plan to migrate, then read on.

The one I will be used for this blog post has around 950.000 registered users, and the site is doing great – but that was achieved by some very fine grained performance tuning, and a very high end Azure subscription.

A performance overview 

I have been using ASP.NET membership provider for years, but I have never looked into it from performance aspects. (Even though I have done some very nasty digging to their table structure). And now I have the chance, I realize how bad it is.

It’s a fairly common seen in the aspnet_* tables that the indexes have ApplicationId as the first column. It does not take a database master to know it is a very ineffective way to create an index – in most of the cases, you only have on ApplicationId in your website, making those indexes useless when you want to, for example, query by UserId. This is a rookie mistake – a newbie tends to make order of columns in the index as same as they appear in the table, thinking, that that SQL Server will just do magic to exchange the order for the best performance. It’s not how SQL Server – or in general – RDBMS systems work.

It is OK to be a newbie or to misunderstand some concepts. I had the very same misconception once, and learned my lessons. However, it should not be OK for a framework to make that mistake, and never correct it.

That is the beginning of much bigger problems. Because of the ineffective order of columns, the builtin indexes are as almost useless. That makes the queries, which should be very fast, become unnecessarily slow, wasting resources and increasing your site average response time. This is of course bad news. But good news is it’s in database level, so we can change it for the better. It if were in the application level then our chance of doing that is close to none.

Missing indexes

If you use Membership.GetUserNameByEmail on your website a lot, you might notice that it is … slow. It leads to this query:

        SELECT  u.UserName
        FROM    dbo.aspnet_Applications a, dbo.aspnet_Users u, dbo.aspnet_Membership m
        WHERE   LOWER(@ApplicationName) = a.LoweredApplicationName AND
                u.ApplicationId = a.ApplicationId    AND
                u.UserId = m.UserId AND
                LOWER(@Email) = m.LoweredEmail

Let’s just ignore the style for now (INNER JOIN would be a much more popular choice), and look into the what is actually done here. So it joins 3 tables by their keys. The join with aspnet_Applications would be fairly simple, because you usually have just one application. The join between aspnet_Users and aspnet_Membership is also simple, because both of them have index on UserId – clustered on aspnet_Users and non-clustered on aspnet_Membership

The last one is actually problematic. The clustered index on aspnet_Membership actually looks like this

CREATE CLUSTERED INDEX [aspnet_Membership_index]
    ON [dbo].[aspnet_Membership]([ApplicationId] ASC, [LoweredEmail] ASC);

Uh oh. Even if this contains LoweredEmail, it’s the worst possible kind of index. By using the least distinctive column in the first, it defeats the purpose of the index completely. Every request to get user name by email address will need to perform a full table scan (oops!)

This is a the last thing you want to see in a execution plan, especially with a fairly big table. 

It should have been just

CREATE CLUSTERED INDEX [aspnet_Membership_index]
    ON [dbo].[aspnet_Membership]([LoweredEmail] ASC);

which helps SQL Server to use the optimal execution plan

If you look into Azure SQL Database recommendation, it suggest you to create a non clustered index on LoweredEmail. That is not technically incorrect, and it still helps. However, keep in mind that each non clustered index will have to “duplicate” the clustered index, for the purpose of identify the rows, so keeping the useless clustered index actually increases wastes and slows down performance (even just a little, because you have to perform more reads to get the same data). However, if your database is currently performing badly, adding a non clustered index is a much quicker and safer option. The change to clustered index should be done with caution at low traffic time.

Tested the stored procedure on database above, without any additional index

Table 'aspnet_Membership'. Scan count 9, logical reads 20101, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'aspnet_Applications'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'aspnet_Users'. Scan count 0, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 237 ms,  elapsed time = 182 ms.

With new non clustered index


(1 row affected)
Table 'aspnet_Applications'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'aspnet_Users'. Scan count 0, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'aspnet_Membership'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 15 ms,  elapsed time = 89 ms.

With new clustered index:

(1 row affected)
Table 'aspnet_Applications'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'aspnet_Users'. Scan count 0, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'aspnet_Membership'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 89 ms.

Don’t we have a clear winner?