Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibly incorrect index precedence for SQL queries #440

Open
erikvk opened this issue Sep 4, 2018 · 6 comments
Open

Possibly incorrect index precedence for SQL queries #440

erikvk opened this issue Sep 4, 2018 · 6 comments

Comments

@erikvk
Copy link

erikvk commented Sep 4, 2018

@miyconst

I have a database class Mopedo.Database.Device (see below for class definition). I have a couple of indexes on this table:

[{
  "Name": "Device_IP",
  "ResourceName": "Mopedo.Database.Device",
  "Provider": "StarcounterDeclared",
  "Columns": [{
    "Name": "IP",
    "Descending": false
  }]
}, {
  "Name": "Device_UsedCount",
  "ResourceName": "Mopedo.Database.Device",
  "Provider": "StarcounterDeclared",
  "Columns": [{
    "Name": "UsedCount",
    "Descending": true
  }]
}]

My issue is that the index used in ORDER BY clauses in SQL statements have precedence over any index that could be used to evaluate the WHERE clause(s), even though WHERE is evaluated before ORDER BY. This seems wrong to me – and makes some of our queries, like in example 3 below, many times slower.

Example 1

SQL query 1:

SELECT IP FROM Mopedo.Database.Device ORDER BY UsedCount

Query plan 1:

Tables(
 0 = Mopedo.Database.Device
)
Projection(
 0 = 
  StringProperty(0, IP)
)
IndexScan(
 Device_UsedCount ON Mopedo.Database.Device
 0
 UsedCount
 IntegerDynamicRange(
 )
 LogicalValue(TRUE)
 Descending
)

Here the Device_UsedCount index is used, which of course is what we want.

Example 2

SQL query 2:

SELECT IP FROM Mopedo.Database.Device WHERE IP = '127.0.0.1'

Query plan 2:

Tables(
 0 = Mopedo.Database.Device
)
Projection(
 0 = 
  StringProperty(0, IP)
)
IndexScan(
 Device_IP ON Mopedo.Database.Device
 0
 IP
 StringDynamicRange(
  StringRangePoint(
   GreaterThanOrEqual
   StringLiteral(127.0.0.1)
  )
  StringRangePoint(
   LessThanOrEqual
   StringLiteral(127.0.0.1)
  )
 )
 LogicalValue(TRUE)
 Ascending
)

Here the Device_IP index is used, which – again – is what we expect.

Example 3

SQL query 3:

SELECT IP FROM Mopedo.Database.Device WHERE IP = '127.0.0.1' ORDER BY UsedCount

Query plan 3:

Tables(
 0 = Mopedo.Database.Device
)
Projection(
 0 = 
  StringProperty(0, IP)
)
IndexScan(
 Device_UsedCount ON Mopedo.Database.Device
 0
 UsedCount
 IntegerDynamicRange(
 )
 ComparisonString(
  Equal
  StringProperty(0, IP)
  StringLiteral(127.0.0.1)
 )
 Descending
)

Here the Device_UsedCount index takes precedence over Device_IP, which is clearly not the fastest way to evaluate the query. You could argue that ORDER BY should only be used when expecting multiple result rows – but still my conjecture is that using the index on WHERE (especially if the table contains thousands and thousands of rows like in this case) should be more efficient. Please correct me if I'm wrong about this.

Mopedo.Database.Device definition

[Database, RESTar]
public class Device : IDataSource, IDatabaseResource, IEntity
{
    [Key] public string IP { get; }
    public string BrowserUserAgent { get; internal set; }
    public Geo Geo { get; internal set; }
    public bool? DoNotTrack { get; internal set; }
    public string Ifa { get; internal set; }
    public int? DeviceType { get; internal set; }
    public string Make { get; internal set; }
    public string Model { get; internal set; }
    public string OperatingSystem { get; internal set; }
    public string OperatingSystemVersion { get; internal set; }
    public bool? JavaScriptSupported { get; internal set; }
    public string FlashVersionSupported { get; internal set; }
    public string Language { get; internal set; }
    public string Carrier { get; internal set; }
    public int? ConnectionType { get; internal set; }
    public string SHA1HashedDeviceId { get; internal set; }
    public string MD5HashedDeviceId { get; internal set; }
    public string SHA1HashedPlatformId { get; internal set; }
    public string MD5HashedPlatformId { get; internal set; }
    public DateTime? MatchedAt { get; private set; }
    [RESTarMember(readOnly: true)] public DateTime CreatedAt { get; set; }
    [RESTarMember(readOnly: true)] public DateTime UsedAt { get; set; }
    [RESTarMember(readOnly: true)] public long UsedCount { get; set; }
    [RESTarMember(readOnly: true)] public long UsedRank { get; set; }
    public DeviceExtension Extension
    {
        get => Db.SQL<DeviceExtension>(DeviceExtension.ByDevice, this).FirstOrDefault();
        set
        {
            if (value == null) Extension?.Delete();
            else value[nameof(IP)] = IP;
        }
    }
}
@erikvk
Copy link
Author

erikvk commented Sep 4, 2018

Version=2.3.2.930

@erikvk
Copy link
Author

erikvk commented Sep 4, 2018

(note that this is not a big problem for us in our apps – I will just add index hints for the problematic queries in my code)

@k-rus
Copy link

k-rus commented Sep 5, 2018

Thank you for reporting.

@un-tone Can you check the issue?

cc @miyconst

@un-tone
Copy link

un-tone commented Sep 7, 2018

@k-rus I confirm the issue.

@un-tone
Copy link

un-tone commented Sep 12, 2018

@bigwad votes to close the issue as won't fix.

cc @miyconst

@miyconst
Copy link

@un-tone, @bigwad thank you for checking the issue. I am going to keep it as later and see when/if we can fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants